@@ -2085,6 +2085,14 @@ HttpTransact::OSDNSLookup(State *s)
20852085 } else if (s->cache_lookup_result == CACHE_LOOKUP_MISS || s->cache_info .action == CACHE_DO_NO_ACTION) {
20862086 TRANSACT_RETURN (SM_ACTION_API_OS_DNS, HandleCacheOpenReadMiss);
20872087 // DNS lookup is done if the lookup failed and need to call Handle Cache Open Read Miss
2088+ } else if (s->cache_info .action == CACHE_PREPARE_TO_WRITE && s->http_config_param ->cache_post_method == 1 &&
2089+ s->method == HTTP_WKSIDX_POST) {
2090+ // By virtue of being here, we are intending to forward the request on
2091+ // to the server. If we marked this as CACHE_PREPARE_TO_WRITE and this
2092+ // is a POST request whose response we intend to write, then we have to
2093+ // proceed from here by calling the function that handles this as a
2094+ // miss.
2095+ TRANSACT_RETURN (SM_ACTION_API_OS_DNS, HandleCacheOpenReadMiss);
20882096 } else {
20892097 build_error_response (s, HTTP_STATUS_INTERNAL_SERVER_ERROR, " Invalid Cache Lookup result" , " default" );
20902098 Log::error (" HTTP: Invalid CACHE LOOKUP RESULT : %d" , s->cache_lookup_result );
@@ -3093,7 +3101,8 @@ HttpTransact::build_response_from_cache(State *s, HTTPWarningCode warning_code)
30933101 // fall through
30943102 default :
30953103 SET_VIA_STRING (VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_HIT_SERVED);
3096- if (s->method == HTTP_WKSIDX_GET || s->api_resp_cacheable == true ) {
3104+ if (s->method == HTTP_WKSIDX_GET || (s->http_config_param ->cache_post_method == 1 && s->method == HTTP_WKSIDX_POST) ||
3105+ s->api_resp_cacheable == true ) {
30973106 // send back the full document to the client.
30983107 TxnDebug (" http_trans" , " [build_response_from_cache] Match! Serving full document." );
30993108 s->cache_info .action = CACHE_DO_SERVE;
@@ -3323,7 +3332,7 @@ HttpTransact::HandleCacheOpenReadMiss(State *s)
33233332 if (GET_VIA_STRING (VIA_DETAIL_CACHE_LOOKUP) == ' ' ) {
33243333 SET_VIA_STRING (VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_NOT_CACHED);
33253334 }
3326- // We do a cache lookup for DELETE and PUT requests as well.
3335+ // We do a cache lookup for some non-GET requests as well.
33273336 // We must, however, not cache the responses to these requests.
33283337 if (does_method_require_cache_copy_deletion (s->http_config_param , s->method ) && s->api_req_cacheable == false ) {
33293338 s->cache_info .action = CACHE_DO_NO_ACTION;
@@ -4475,10 +4484,11 @@ HttpTransact::handle_cache_operation_on_forward_server_response(State *s)
44754484 // cacheability of server response, and request method
44764485 // precondition: s->cache_info.action is one of the following
44774486 // CACHE_DO_UPDATE, CACHE_DO_WRITE, or CACHE_DO_DELETE
4487+ int const server_request_method = s->hdr_info .server_request .method_get_wksidx ();
44784488 if (s->api_server_response_no_store ) {
44794489 s->cache_info .action = CACHE_DO_NO_ACTION;
44804490 } else if (s->api_server_response_ignore && server_response_code == HTTP_STATUS_OK &&
4481- s-> hdr_info . server_request . method_get_wksidx () == HTTP_WKSIDX_HEAD) {
4491+ server_request_method == HTTP_WKSIDX_HEAD) {
44824492 s->api_server_response_ignore = false ;
44834493 ink_assert (s->cache_info .object_read );
44844494 base_response = s->cache_info .object_read ->response_get ();
@@ -4495,7 +4505,21 @@ HttpTransact::handle_cache_operation_on_forward_server_response(State *s)
44954505 } else if (s->www_auth_content == CACHE_AUTH_STALE && server_response_code == HTTP_STATUS_UNAUTHORIZED) {
44964506 s->cache_info .action = CACHE_DO_NO_ACTION;
44974507 } else if (!cacheable) {
4498- s->cache_info .action = CACHE_DO_DELETE;
4508+ if (HttpTransactHeaders::is_status_an_error_response (server_response_code) &&
4509+ !HttpTransactHeaders::is_method_safe (server_request_method)) {
4510+ // Only delete the cache entry if the response is successful. For
4511+ // unsuccessful responses, the transaction doesn't invalidate our
4512+ // entry. This behavior complies with RFC 7234, section 4.4 which
4513+ // stipulates that the entry only need be invalidated for non-error
4514+ // responses:
4515+ //
4516+ // A cache MUST invalidate the effective request URI (Section 5.5 of
4517+ // [RFC7230]) when it receives a non-error response to a request
4518+ // with a method whose safety is unknown.
4519+ s->cache_info .action = CACHE_DO_NO_ACTION;
4520+ } else {
4521+ s->cache_info .action = CACHE_DO_DELETE;
4522+ }
44994523 } else if (s->method == HTTP_WKSIDX_HEAD) {
45004524 s->cache_info .action = CACHE_DO_DELETE;
45014525 } else {
@@ -4513,7 +4537,19 @@ HttpTransact::handle_cache_operation_on_forward_server_response(State *s)
45134537 }
45144538
45154539 } else if (s->cache_info .action == CACHE_DO_DELETE) {
4516- // do nothing
4540+ if (!cacheable && HttpTransactHeaders::is_status_an_error_response (server_response_code) &&
4541+ !HttpTransactHeaders::is_method_safe (server_request_method)) {
4542+ // Only delete the cache entry if the response is successful. For
4543+ // unsuccessful responses, the transaction doesn't invalidate our
4544+ // entry. This behavior complies with RFC 7234, section 4.4 which
4545+ // stipulates that the entry only need be invalidated for non-error
4546+ // responses:
4547+ //
4548+ // A cache MUST invalidate the effective request URI (Section 5.5 of
4549+ // [RFC7230]) when it receives a non-error response to a request
4550+ // with a method whose safety is unknown.
4551+ s->cache_info .action = CACHE_DO_NO_ACTION;
4552+ }
45174553
45184554 } else {
45194555 ink_assert (!(" cache action inconsistent with current state" ));
@@ -5920,6 +5956,18 @@ HttpTransact::is_cache_response_returnable(State *s)
59205956 SET_VIA_STRING (VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_METHOD);
59215957 return false ;
59225958 }
5959+ // We may be caching responses to methods other than GET, such as POST. Make
5960+ // sure that our cached resource has a method that matches the incoming
5961+ // requests's method. If not, then we cannot reply with the cached resource.
5962+ // That is, we cannot reply to an incoming GET request with a response to a
5963+ // previous POST request.
5964+ int const client_request_method = s->hdr_info .client_request .method_get_wksidx ();
5965+ int const cached_request_method = s->cache_info .object_read ->request_get ()->method_get_wksidx ();
5966+ if (client_request_method != cached_request_method) {
5967+ SET_VIA_STRING (VIA_CACHE_RESULT, VIA_IN_CACHE_NOT_ACCEPTABLE);
5968+ SET_VIA_STRING (VIA_DETAIL_CACHE_LOOKUP, VIA_DETAIL_MISS_METHOD);
5969+ return false ;
5970+ }
59235971 // If cookies in response and no TTL set, we do not cache the doc
59245972 if ((s->cache_control .ttl_in_cache <= 0 ) &&
59255973 do_cookies_prevent_caching (static_cast <int >(s->txn_conf ->cache_responses_to_cookies ), &s->hdr_info .client_request ,
0 commit comments