src/ngx_pagespeed.cc
// PSOL produces caching headers that need some changes before we can send them
// out.  Make those changes and populate r->headers_out from pagespeed_headers.
PSOL produces caching headers that need some changes before we can send them
out.  Make those changes and populate r->headers_out from pagespeed_headers.
PSOL produces caching headers that need some changes before we can send them out . Make those changes and populate r - > headers_out from pagespeed_headers .
ngx_int_t copy_response_headers_to_ngx(
    ngx_http_request_t* r,
    const ResponseHeaders& pagespeed_headers,
    PreserveCachingHeaders preserve_caching_headers) {
  ngx_http_headers_out_t* headers_out = &r->headers_out;
  headers_out->status = pagespeed_headers.status_code();
  ngx_int_t i;
  for (i = 0 ; i < pagespeed_headers.NumAttributes() ; i++) {
    const GoogleString& name_gs = pagespeed_headers.Name(i);
    const GoogleString& value_gs = pagespeed_headers.Value(i);
    if (preserve_caching_headers == kPreserveAllCachingHeaders) {
      if (StringCaseEqual(name_gs, "ETag") ||
          StringCaseEqual(name_gs, "Expires") ||
          StringCaseEqual(name_gs, "Date") ||
          StringCaseEqual(name_gs, "Last-Modified") ||
          StringCaseEqual(name_gs, "Cache-Control")) {
        continue;
      }
    } else if (preserve_caching_headers == kPreserveOnlyCacheControl) {
      if (StringCaseEqual(name_gs, "Cache-Control")) {
        continue;
      }
    }  
    ngx_str_t name, value;
    value.len = value_gs.size();
    value.data = reinterpret_cast<u_char*>(
        string_piece_to_pool_string(r->pool, value_gs.c_str()));
    if (StringCaseEqual(name_gs, "etag")
        && StringCaseStartsWith(value_gs, "W/")) {
      name.len = strlen(kInternalEtagName);
      name.data = reinterpret_cast<u_char*>(
          const_cast<char*>(kInternalEtagName));
    } else {
      name.len = name_gs.size();
      name.data = reinterpret_cast<u_char*>(
          string_piece_to_pool_string(r->pool, name_gs.c_str()));
    }
    if (name.data == NULL || value.data == NULL) {
        return NGX_ERROR;
    }
    if (STR_EQ_LITERAL(name, "Cache-Control")) {
      ps_set_cache_control(r, reinterpret_cast<char*>(value.data));
      continue;
    } else if (STR_EQ_LITERAL(name, "Content-Type")) {
      headers_out->content_type = value;
      for (ngx_uint_t i = 0; i < value.len; i++) {
        if (value.data[i] == ';') {
          break;
        }
        headers_out->content_type_len = i + 1;
      }
      headers_out->content_type_lowcase = NULL;
      continue;
    } else if (STR_EQ_LITERAL(name, "Connection")) {
      continue;
    } else if (STR_EQ_LITERAL(name, "Keep-Alive")) {
      continue;
    } else if (STR_EQ_LITERAL(name, "Transfer-Encoding")) {
      continue;
    } else if (STR_EQ_LITERAL(name, "Vary") && value.len
        && STR_EQ_LITERAL(value, "Accept-Encoding")) {
      ps_request_ctx_t* ctx = ps_get_request_context(r);
      ctx->psol_vary_accept_only = true;
    }
    ngx_table_elt_t* header = static_cast<ngx_table_elt_t*>(
        ngx_list_push(&headers_out->headers));
    if (header == NULL) {
      return NGX_ERROR;
    }
    header->hash = 1;  
    header->key.data = name.data;
    header->key.len = name.len;
    header->value.data = value.data;
    header->value.len = value.len;
    if (STR_EQ_LITERAL(name, "Date")) {
      headers_out->date = header;
    } else if (STR_EQ_LITERAL(name, "Etag")) {
      headers_out->etag = header;
    } else if (STR_EQ_LITERAL(name, "Expires")) {
      headers_out->expires = header;
    } else if (STR_EQ_LITERAL(name, "Last-Modified")) {
      headers_out->last_modified = header;
    } else if (STR_EQ_LITERAL(name, "Location")) {
      ps_request_ctx_t* ctx = ps_get_request_context(r);
      if (ctx->location_field_set) {
        headers_out->location = header;
      }
    } else if (STR_EQ_LITERAL(name, "Server")) {
      headers_out->server = header;
    } else if (STR_EQ_LITERAL(name, "Content-Length")) {
      int64 len;
      CHECK(pagespeed_headers.FindContentLength(&len));
      headers_out->content_length_n = len;
      headers_out->content_length = header;
    } else if (STR_EQ_LITERAL(name, "Content-Encoding")) {
      headers_out->content_encoding = header;
    } else if (STR_EQ_LITERAL(name, "Refresh")) {
      headers_out->refresh = header;
    } else if (STR_EQ_LITERAL(name, "Content-Range")) {
      headers_out->content_range = header;
    } else if (STR_EQ_LITERAL(name, "Accept-Ranges")) {
      headers_out->accept_ranges = header;
    } else if (STR_EQ_LITERAL(name, "WWW-Authenticate")) {
      headers_out->www_authenticate = header;
    }
  }
  return NGX_OK;
}
ngx_int_t copy_response_headers_to_ngx ( ngx_http_request_t * r , const ResponseHeaders & pagespeed_headers , PreserveCachingHeaders preserve_caching_headers ) { ngx_http_headers_out_t * headers_out = & r -> headers_out ; headers_out -> status = pagespeed_headers . status_code ( ) ; ngx_int_t i ; for ( i = 0 ; i < pagespeed_headers . NumAttributes ( ) ; i ++ ) { const GoogleString & name_gs = pagespeed_headers . Name ( i ) ; const GoogleString & value_gs = pagespeed_headers . Value ( i ) ; if ( preserve_caching_headers == kPreserveAllCachingHeaders ) { if ( StringCaseEqual ( name_gs , " " ) || StringCaseEqual ( name_gs , " " ) || StringCaseEqual ( name_gs , " " ) || StringCaseEqual ( name_gs , " " ) || StringCaseEqual ( name_gs , " " ) ) { continue ; } } else if ( preserve_caching_headers == kPreserveOnlyCacheControl ) { if ( StringCaseEqual ( name_gs , " " ) ) { continue ; } } ngx_str_t name , value ; value . len = value_gs . size ( ) ; value . data = reinterpret_cast < u_char * > ( string_piece_to_pool_string ( r -> pool , value_gs . c_str ( ) ) ) ; if ( StringCaseEqual ( name_gs , " " ) && StringCaseStartsWith ( value_gs , " " ) ) { name . len = strlen ( kInternalEtagName ) ; name . data = reinterpret_cast < u_char * > ( const_cast < char * > ( kInternalEtagName ) ) ; } else { name . len = name_gs . size ( ) ; name . data = reinterpret_cast < u_char * > ( string_piece_to_pool_string ( r -> pool , name_gs . c_str ( ) ) ) ; } if ( name . data == NULL || value . data == NULL ) { return NGX_ERROR ; } if ( STR_EQ_LITERAL ( name , " " ) ) { ps_set_cache_control ( r , reinterpret_cast < char * > ( value . data ) ) ; continue ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> content_type = value ; for ( ngx_uint_t i = 0 ; i < value . len ; i ++ ) { if ( value . data [ i ] == ' ' ) { break ; } headers_out -> content_type_len = i + 1 ; } headers_out -> content_type_lowcase = NULL ; continue ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { continue ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { continue ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { continue ; } else if ( STR_EQ_LITERAL ( name , " " ) && value . len && STR_EQ_LITERAL ( value , " " ) ) { ps_request_ctx_t * ctx = ps_get_request_context ( r ) ; ctx -> psol_vary_accept_only = true ; } ngx_table_elt_t * header = static_cast < ngx_table_elt_t * > ( ngx_list_push ( & headers_out -> headers ) ) ; if ( header == NULL ) { return NGX_ERROR ; } header -> hash = 1 ; header -> key . data = name . data ; header -> key . len = name . len ; header -> value . data = value . data ; header -> value . len = value . len ; if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> date = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> etag = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> expires = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> last_modified = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { ps_request_ctx_t * ctx = ps_get_request_context ( r ) ; if ( ctx -> location_field_set ) { headers_out -> location = header ; } } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> server = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { int64 len ; CHECK ( pagespeed_headers . FindContentLength ( & len ) ) ; headers_out -> content_length_n = len ; headers_out -> content_length = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> content_encoding = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> refresh = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> content_range = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> accept_ranges = header ; } else if ( STR_EQ_LITERAL ( name , " " ) ) { headers_out -> www_authenticate = header ; } } return NGX_OK ; }
PSOL produces caching headers that need some changes before we can send them
out.
PSOL produces caching headers that need some changes before we can send them out .
// For IPRO cache misses, these gs_ variables may point to freed memory // when nginx writes the headers to the output as the NgxBaseFetch instance // that owns this memory gets released during request processing. So we // copy these strings later on. // Retain the original Cache-Control header, but send the recomputed // values for all other cache-related headers. // else we don't preserve any headers. // To prevent the gzip module from clearing weak etags, we output them // using a different name here. The etag header filter module runs behind // the gzip compressors header filter, and will rename it to 'ETag' // In case string_piece_to_pool_string failed: // TODO(jefftk): If we're setting a cache control header we'd like to // prevent any downstream code from changing it.  Specifically, if we're // serving a cache-extended resource the url will change if the resource // does and so we've given it a long lifetime.  If the site owner has done // something like set all css files to a 10-minute cache lifetime, that // shouldn't apply to our generated resources.  See Apache code in // net/instaweb/apache/header_util:AddResponseHeadersToRequest // Make copies of name and value to put into headers_out. // Unlike all the other headers, content_type is just a string. // We should not include the charset when determining content_type_len, so // scan for the ';' that marks the start of the charset part. // In ngx_http_test_content_type() nginx will allocate and calculate // content_type_lowcase if we leave it as null. // TODO(oschaaf): are there any other headers we should not try to // copy here? // Include this header in the output. // Populate the shortcuts to commonly used headers.