@@ -330,7 +330,7 @@ compress_transform_init(TSCont contp, Data *data)
330330 }
331331
332332 if (content_encoding_header (bufp, hdr_loc, data->compression_type , data->compression_algorithms ) == TS_SUCCESS &&
333- vary_header (bufp, hdr_loc) == TS_SUCCESS && etag_header (bufp, hdr_loc) == TS_SUCCESS) {
333+ etag_header (bufp, hdr_loc) == TS_SUCCESS) {
334334 downstream_conn = TSTransformOutputVConnGet (contp);
335335 data->downstream_buffer = TSIOBufferCreate ();
336336 data->downstream_reader = TSIOBufferReaderAlloc (data->downstream_buffer );
@@ -518,7 +518,7 @@ compress_transform(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
518518}
519519
520520static int
521- transformable (TSHttpTxn txnp, bool server, HostConfiguration *host_configuration, int *compress_type, int *algorithms )
521+ is_content_compressible (TSHttpTxn txnp, bool server, HostConfiguration *host_configuration)
522522{
523523 /* Server response header */
524524 TSMBuffer bufp;
@@ -528,7 +528,6 @@ transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration
528528 /* Client request header */
529529 TSMBuffer cbuf;
530530 TSMLoc chdr;
531- TSMLoc cfield;
532531
533532 const char *value;
534533 int len;
@@ -570,6 +569,100 @@ transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration
570569 return 0 ;
571570 }
572571
572+ // the only compressible method is currently GET or POST.
573+ int method_length;
574+ const char *method = TSHttpHdrMethodGet (cbuf, chdr, &method_length);
575+
576+ if (!((method_length == TS_HTTP_LEN_GET && memcmp (method, TS_HTTP_METHOD_GET, TS_HTTP_LEN_GET) == 0 ) ||
577+ (method_length == TS_HTTP_LEN_POST && memcmp (method, TS_HTTP_METHOD_POST, TS_HTTP_LEN_POST) == 0 ))) {
578+ debug (" method is not GET or POST, not compressible" );
579+ TSHandleMLocRelease (cbuf, TS_NULL_MLOC, chdr);
580+ TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
581+ return 0 ;
582+ }
583+
584+ TSHandleMLocRelease (cbuf, TS_NULL_MLOC, chdr);
585+
586+ /* If there already exists a content encoding then we don't want
587+ to do anything. */
588+ field_loc = TSMimeHdrFieldFind (bufp, hdr_loc, TS_MIME_FIELD_CONTENT_ENCODING, -1 );
589+ if (field_loc) {
590+ info (" response is already content encoded, not compressible" );
591+ TSHandleMLocRelease (bufp, hdr_loc, field_loc);
592+ TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
593+ return 0 ;
594+ }
595+
596+ field_loc = TSMimeHdrFieldFind (bufp, hdr_loc, TS_MIME_FIELD_CONTENT_LENGTH, TS_MIME_LEN_CONTENT_LENGTH);
597+ if (field_loc != TS_NULL_MLOC) {
598+ unsigned int hdr_value = TSMimeHdrFieldValueUintGet (bufp, hdr_loc, field_loc, -1 );
599+ TSHandleMLocRelease (bufp, hdr_loc, field_loc);
600+ if (hdr_value == 0 ) {
601+ info (" response is 0-length, not compressible" );
602+ TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
603+ return 0 ;
604+ }
605+
606+ if (hdr_value < host_configuration->minimum_content_length ()) {
607+ info (" response is smaller than minimum content length, not compressing" );
608+ TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
609+ return 0 ;
610+ }
611+ }
612+
613+ // Check if content type is compressible based on configuration.
614+ field_loc = TSMimeHdrFieldFind (bufp, hdr_loc, TS_MIME_FIELD_CONTENT_TYPE, -1 );
615+ if (!field_loc) {
616+ info (" no content type header found, not compressible" );
617+ TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
618+ return 0 ;
619+ }
620+
621+ value = TSMimeHdrFieldValueStringGet (bufp, hdr_loc, field_loc, -1 , &len);
622+
623+ int rv = host_configuration->is_content_type_compressible (value, len);
624+
625+ if (!rv) {
626+ info (" content-type [%.*s] not compressible" , len, value);
627+ }
628+
629+ TSHandleMLocRelease (bufp, hdr_loc, field_loc);
630+ TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
631+
632+ return rv;
633+ }
634+
635+ static int
636+ client_accepts_compression (TSHttpTxn txnp, bool server, HostConfiguration *host_configuration, int *compress_type, int *algorithms)
637+ {
638+ /* Server response header */
639+ TSMBuffer bufp;
640+ TSMLoc hdr_loc;
641+
642+ /* Client request header */
643+ TSMBuffer cbuf;
644+ TSMLoc chdr;
645+ TSMLoc cfield;
646+
647+ const char *value;
648+ int len;
649+
650+ if (server) {
651+ if (TS_SUCCESS != TSHttpTxnServerRespGet (txnp, &bufp, &hdr_loc)) {
652+ return 0 ;
653+ }
654+ } else {
655+ if (TS_SUCCESS != TSHttpTxnCachedRespGet (txnp, &bufp, &hdr_loc)) {
656+ return 0 ;
657+ }
658+ }
659+
660+ if (TS_SUCCESS != TSHttpTxnClientReqGet (txnp, &cbuf, &chdr)) {
661+ info (" cound not get client request" );
662+ TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
663+ return 0 ;
664+ }
665+
573666 // check Partial Object is transformable
574667 if (host_configuration->range_request_ctl () == RangeRequestCtrl::NO_COMPRESSION) {
575668 // check Range header in client request
@@ -592,21 +685,6 @@ transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration
592685 TSHandleMLocRelease (cbuf, TS_NULL_MLOC, chdr);
593686 return 0 ;
594687 }
595-
596- TSHandleMLocRelease (bufp, hdr_loc, content_range_hdr_field);
597- TSHandleMLocRelease (cbuf, chdr, range_hdr_field);
598- }
599-
600- // the only compressible method is currently GET.
601- int method_length;
602- const char *method = TSHttpHdrMethodGet (cbuf, chdr, &method_length);
603-
604- if (!((method_length == TS_HTTP_LEN_GET && memcmp (method, TS_HTTP_METHOD_GET, TS_HTTP_LEN_GET) == 0 ) ||
605- (method_length == TS_HTTP_LEN_POST && memcmp (method, TS_HTTP_METHOD_POST, TS_HTTP_LEN_POST) == 0 ))) {
606- debug (" method is not GET or POST, not compressible" );
607- TSHandleMLocRelease (cbuf, TS_NULL_MLOC, chdr);
608- TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
609- return 0 ;
610688 }
611689
612690 *algorithms = host_configuration->compression_algorithms ();
@@ -647,10 +725,10 @@ transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration
647725
648726 TSHandleMLocRelease (cbuf, chdr, cfield);
649727 TSHandleMLocRelease (cbuf, TS_NULL_MLOC, chdr);
728+ TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
650729
651730 if (!compression_acceptable) {
652731 info (" no acceptable encoding match found in request header, not compressible" );
653- TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
654732 return 0 ;
655733 }
656734 } else {
@@ -661,52 +739,48 @@ transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration
661739 return 0 ;
662740 }
663741
664- /* If there already exists a content encoding then we don't want
665- to do anything. */
666- field_loc = TSMimeHdrFieldFind (bufp, hdr_loc, TS_MIME_FIELD_CONTENT_ENCODING, -1 );
667- if (field_loc) {
668- info (" response is already content encoded, not compressible" );
669- TSHandleMLocRelease (bufp, hdr_loc, field_loc);
670- TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
671- return 0 ;
672- }
673-
674- field_loc = TSMimeHdrFieldFind (bufp, hdr_loc, TS_MIME_FIELD_CONTENT_LENGTH, TS_MIME_LEN_CONTENT_LENGTH);
675- if (field_loc != TS_NULL_MLOC) {
676- unsigned int hdr_value = TSMimeHdrFieldValueUintGet (bufp, hdr_loc, field_loc, -1 );
677- TSHandleMLocRelease (bufp, hdr_loc, field_loc);
678- if (hdr_value == 0 ) {
679- info (" response is 0-length, not compressible" );
680- return 0 ;
681- }
682-
683- if (hdr_value < host_configuration->minimum_content_length ()) {
684- info (" response is smaller than minimum content length, not compressing" );
685- return 0 ;
686- }
687- }
742+ return 1 ;
743+ }
688744
689- /* We only want to do gzip compression on documents that have a
690- content type of "text/" or "application/x-javascript". */
691- field_loc = TSMimeHdrFieldFind (bufp, hdr_loc, TS_MIME_FIELD_CONTENT_TYPE, -1 );
692- if (!field_loc) {
693- info (" no content type header found, not compressible" );
694- TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
745+ static int
746+ transformable (TSHttpTxn txnp, bool server, HostConfiguration *host_configuration, int *compress_type, int *algorithms,
747+ bool *content_is_compressible)
748+ {
749+ // First check if content could be compressible
750+ *content_is_compressible = is_content_compressible (txnp, server, host_configuration);
751+ if (!*content_is_compressible) {
695752 return 0 ;
696753 }
697754
698- value = TSMimeHdrFieldValueStringGet (bufp, hdr_loc, field_loc, -1 , &len);
755+ // Then check if client accepts compression
756+ return client_accepts_compression (txnp, server, host_configuration, compress_type, algorithms);
757+ }
699758
700- int rv = host_configuration->is_content_type_compressible (value, len);
759+ static void
760+ add_vary_header_for_compressible_content (TSHttpTxn txnp, bool server, HostConfiguration * /* hc ATS_UNUSED */ )
761+ {
762+ TSMBuffer resp_buf;
763+ TSMLoc resp_loc;
701764
702- if (!rv) {
703- info (" content-type [%.*s] not compressible" , len, value);
765+ // Get the response headers
766+ if (server) {
767+ if (TS_SUCCESS != TSHttpTxnServerRespGet (txnp, &resp_buf, &resp_loc)) {
768+ return ;
769+ }
770+ } else {
771+ if (TS_SUCCESS != TSHttpTxnCachedRespGet (txnp, &resp_buf, &resp_loc)) {
772+ return ;
773+ }
704774 }
705775
706- TSHandleMLocRelease (bufp, hdr_loc, field_loc);
707- TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
776+ // Add Vary: Accept-Encoding header
777+ if (vary_header (resp_buf, resp_loc) != TS_SUCCESS) {
778+ error (" failed to add Vary header for compressible content" );
779+ TSHandleMLocRelease (resp_buf, TS_NULL_MLOC, resp_loc);
780+ return ;
781+ }
708782
709- return rv ;
783+ TSHandleMLocRelease (resp_buf, TS_NULL_MLOC, resp_loc) ;
710784}
711785
712786static void
@@ -734,6 +808,21 @@ compress_transform_add(TSHttpTxn txnp, HostConfiguration *hc, int compress_type,
734808 TSHttpTxnHookAdd (txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
735809}
736810
811+ static void
812+ handle_compression_and_vary (TSHttpTxn txnp, bool server, HostConfiguration *hc, int *compress_type, int *algorithms)
813+ {
814+ // Check if content is compressible and add compression if client accepts it
815+ bool content_is_compressible;
816+ if (transformable (txnp, server, hc, compress_type, algorithms, &content_is_compressible)) {
817+ compress_transform_add (txnp, hc, *compress_type, *algorithms);
818+ }
819+
820+ // Add Vary: Accept-Encoding for all compressible content to ensure proper HTTP caching
821+ if (content_is_compressible) {
822+ add_vary_header_for_compressible_content (txnp, server, hc);
823+ }
824+ }
825+
737826HostConfiguration *
738827find_host_configuration (TSHttpTxn /* txnp ATS_UNUSED */ , TSMBuffer bufp, TSMLoc locp, Configuration *config)
739828{
@@ -778,9 +867,7 @@ transform_plugin(TSCont contp, TSEvent event, void *edata)
778867 }
779868 }
780869
781- if (transformable (txnp, true , hc, &compress_type, &algorithms)) {
782- compress_transform_add (txnp, hc, compress_type, algorithms);
783- }
870+ handle_compression_and_vary (txnp, true , hc, &compress_type, &algorithms);
784871 }
785872 break ;
786873
@@ -806,9 +893,7 @@ transform_plugin(TSCont contp, TSEvent event, void *edata)
806893 if (TS_ERROR != TSHttpTxnCacheLookupStatusGet (txnp, &obj_status) && (TS_CACHE_LOOKUP_HIT_FRESH == obj_status)) {
807894 if (hc != nullptr ) {
808895 info (" handling compression of cached object" );
809- if (transformable (txnp, false , hc, &compress_type, &algorithms)) {
810- compress_transform_add (txnp, hc, compress_type, algorithms);
811- }
896+ handle_compression_and_vary (txnp, false , hc, &compress_type, &algorithms);
812897 }
813898 } else {
814899 // Prepare for going to origin
0 commit comments