@@ -492,6 +492,10 @@ ngx_int_t copy_response_headers_to_ngx(
492492
493493 ngx_int_t i;
494494 for (i = 0 ; i < pagespeed_headers.NumAttributes () ; i++) {
495+ // For IPRO cache misses, these gs_ variables may point to freed memory
496+ // when nginx writes the headers to the output as the NgxBaseFetch instance
497+ // that owns this memory gets released during request processing. So we
498+ // copy these strings later on.
495499 const GoogleString& name_gs = pagespeed_headers.Name (i);
496500 const GoogleString& value_gs = pagespeed_headers.Value (i);
497501
@@ -512,6 +516,9 @@ ngx_int_t copy_response_headers_to_ngx(
512516 } // else we don't preserve any headers.
513517
514518 ngx_str_t name, value;
519+ value.len = value_gs.size ();
520+ value.data = reinterpret_cast <u_char*>(
521+ string_piece_to_pool_string (r->pool , value_gs.c_str ()));
515522
516523 // To prevent the gzip module from clearing weak etags, we output them
517524 // using a different name here. The etag header filter module runs behind
@@ -522,11 +529,15 @@ ngx_int_t copy_response_headers_to_ngx(
522529 name.data = reinterpret_cast <u_char*>(
523530 const_cast <char *>(kInternalEtagName ));
524531 } else {
525- name.len = name_gs.length ();
526- name.data = reinterpret_cast <u_char*>(const_cast <char *>(name_gs.data ()));
532+ name.len = name_gs.size ();
533+ name.data = reinterpret_cast <u_char*>(
534+ string_piece_to_pool_string (r->pool , name_gs.c_str ()));
535+ }
536+
537+ // In case string_piece_to_pool_string failed:
538+ if (name.data == NULL || value.data == NULL ) {
539+ return NGX_ERROR;
527540 }
528- value.len = value_gs.length ();
529- value.data = reinterpret_cast <u_char*>(const_cast <char *>(value_gs.data ()));
530541
531542 // TODO(jefftk): If we're setting a cache control header we'd like to
532543 // prevent any downstream code from changing it. Specifically, if we're
@@ -537,24 +548,17 @@ ngx_int_t copy_response_headers_to_ngx(
537548 // net/instaweb/apache/header_util:AddResponseHeadersToRequest
538549
539550 // Make copies of name and value to put into headers_out.
540-
541- u_char* value_s = ngx_pstrdup (r->pool , &value);
542- if (value_s == NULL ) {
543- return NGX_ERROR;
544- }
545-
546551 if (STR_EQ_LITERAL (name, " Cache-Control" )) {
547- ps_set_cache_control (r, const_cast <char *>(value_gs. c_str () ));
552+ ps_set_cache_control (r, reinterpret_cast <char *>(value. data ));
548553 continue ;
549554 } else if (STR_EQ_LITERAL (name, " Content-Type" )) {
550555 // Unlike all the other headers, content_type is just a string.
551- headers_out->content_type .data = value_s;
552- headers_out->content_type .len = value.len ;
556+ headers_out->content_type = value;
553557
554558 // We should not include the charset when determining content_type_len, so
555559 // scan for the ';' that marks the start of the charset part.
556560 for (ngx_uint_t i = 0 ; i < value.len ; i++) {
557- if (value_s [i] == ' ;' ) {
561+ if (value. data [i] == ' ;' ) {
558562 break ;
559563 }
560564 headers_out->content_type_len = i + 1 ;
@@ -574,22 +578,17 @@ ngx_int_t copy_response_headers_to_ngx(
574578 continue ;
575579 }
576580
577- u_char* name_s = ngx_pstrdup (r->pool , &name);
578- if (name_s == NULL ) {
579- return NGX_ERROR;
580- }
581-
582581 ngx_table_elt_t * header = static_cast <ngx_table_elt_t *>(
583582 ngx_list_push (&headers_out->headers ));
584583 if (header == NULL ) {
585584 return NGX_ERROR;
586585 }
587586
588587 header->hash = 1 ; // Include this header in the output.
588+ header->key .data = name.data ;
589589 header->key .len = name.len ;
590- header->key .data = name_s ;
590+ header->value .data = value. data ;
591591 header->value .len = value.len ;
592- header->value .data = value_s;
593592
594593 // Populate the shortcuts to commonly used headers.
595594 if (STR_EQ_LITERAL (name, " Date" )) {
0 commit comments