def _final_wsgi_response(self, environ, msite, reqinfo, resp, src_resp_body): logger.info("Passing through response for {}".format(reqinfo.url)) return _passthrough_response(src_resp_body, resp)
def wsgi_response(self, msite, environ, start_response): """ Generate the WSGI response FAKING HEAD REQUESTS According to HTTP 1.1, HTTP HEAD requests are supposed to elicit the exact same response headers as a GET request, with an empty response body. But some real-world web servers don't follow this, and may return a 500 or some other error. This has affected our uptime monitoring for at least one client, since the third-party monitoring we use checks the server via an HTTP HEAD request to the home page. To deal with this, we fake such HEAD requests by (1) converting them to a GET request; (2) discarding the response body; and (3) adding an X-MWU-Info response header describing what we have done. TODO: Have this disablable by the msite, controlled by a boolean setting in defs.py @param msite : Mobile site @type msite : MobileSite @param environ : WSGI environment @type environ : dict @param start_response : WSGI start_response callable @type start_response : callable @return : Final body components @rtype : list of str """ from mobilize.log import format_headers_log logger.info("Matching moplate: {}".format(self.name)) reqinfo = httputil.RequestInfo(environ) for sechook in msite.sechooks(): sechook.check_request(reqinfo) fake_head_req = msite.must_fake_http_head(reqinfo) http = msite.get_http() request_overrides = msite.request_overrides(environ) logger.info(format_headers_log("NEW: raw request headers", reqinfo, list(reqinfo.iterrawheaders()))) request_headers = reqinfo.headers(request_overrides) logger.info(format_headers_log("modified request headers", reqinfo, request_headers)) source_url = reqinfo.root_url + self.source_rel_url(reqinfo.rel_url) if fake_head_req: reqinfo.method = "GET" resp, src_resp_bytes = http.request( source_url, method=reqinfo.method, body=reqinfo.body, headers=request_headers ) if fake_head_req: reqinfo.method = "HEAD" # restore original method src_resp_bytes = b"" logger.info(format_headers_log("raw response headers", reqinfo, resp, status=resp.status)) charset = httputil.guess_charset(resp, src_resp_bytes, msite.default_charset) status = "%s %s" % (resp.status, resp.reason) # Note that for us to mobilize the response, both the request # AND the response must be "mobilizeable". if reqinfo.mobilizeable and httputil.mobilizeable(resp): src_resp_body = httputil.netbytes2str(src_resp_bytes, charset) final_body, final_resp_headers = self._final_wsgi_response(environ, msite, reqinfo, resp, src_resp_body) else: # TODO: must apply response overrides, at least for 301/302 redirs for one specific client final_resp_headers = httputil.dict2list(resp) final_body = src_resp_bytes final_resp_headers = msite.postprocess_response_headers(final_resp_headers, resp.status) assert type(final_resp_headers) == list if fake_head_req: final_resp_headers.append(("X-MWU-Info", "Faked HEAD request as GET on source server")) logger.info(format_headers_log("final resp headers", reqinfo, final_resp_headers)) # TODO: if the next line raises a TypeError, catch it and log final_resp_headers in detail (and everything else while we're at it) start_response(status, final_resp_headers) return [final_body]