Example #1
0
 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)
Example #2
0
    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]