Esempio n. 1
0
    def _RenderResponse(self, request):
        response = http_api.RenderHttpResponse(request)

        if response.content.startswith(")]}'\n"):
            response.content = response.content[5:]

        return response
Esempio n. 2
0
    def Check(self, method, url, payload=None, replace=None):
        """Records output of a given url accessed with a given method.

    Args:
      method: HTTP method. May be "GET" or "POST".
      url: String repesenting an url.
      payload: JSON-able payload that will be sent when "POST" method is used.
      replace: Dictionary of key->value pairs. In the recorded JSON output
               every "key" string will be replaced with its "value"
               counterpart. This way we can properly handle dynamically
               generated values (like hunts IDs) in the regression data.
    Raises:
      ValueError: if unsupported method argument is passed. Currently only
                  "GET" is supported.
    """
        parsed_url = urlparse.urlparse(url)
        request = utils.DataObject(method=method,
                                   scheme="http",
                                   path=parsed_url.path,
                                   environ={
                                       "SERVER_NAME": "foo.bar",
                                       "SERVER_PORT": 1234
                                   },
                                   user="******")
        request.META = {"CONTENT_TYPE": "application/json"}

        if method == "GET":
            request.GET = dict(urlparse.parse_qsl(parsed_url.query))
        elif method == "POST":
            request.body = json.dumps(payload)
        else:
            raise ValueError("Unsupported method: %s." % method)

        with self.NoAuthorizationChecks():
            http_response = http_api.RenderHttpResponse(request)

        content = http_response.content

        xssi_token = ")]}'\n"
        if content.startswith(xssi_token):
            content = content[len(xssi_token):]

        if replace:
            if hasattr(replace, "__call__"):
                replace = replace()

            for substr, repl in replace.items():
                content = content.replace(substr, repl)
                url = url.replace(substr, repl)

        parsed_content = json.loads(content)
        self.checks.append(
            dict(method=method,
                 url=url,
                 test_class=self.__class__.__name__,
                 response=parsed_content))
Esempio n. 3
0
    def _HandleApi(self, request):
        """Handles API requests."""
        # Checks CSRF token. CSRF token cookie is updated when homepage is visited
        # or via GetPendingUserNotificationsCount API call.
        ValidateCSRFTokenOrRaise(request)

        response = http_api.RenderHttpResponse(request)

        # GetPendingUserNotificationsCount is an API method that is meant
        # to be invoked very often (every 10 seconds). So it's ideal
        # for updating the CSRF token.
        if response.headers.get("X-API-Method",
                                "") == "GetPendingUserNotificationsCount":
            StoreCSRFCookie(request, response)

        return response
Esempio n. 4
0
    def Check(self, method, url, payload=None, replace=None):
        """Records output of a given url accessed with a given method.

    Args:
      method: HTTP method. May be "GET" or "POST".
      url: String repesenting an url.
      payload: JSON-able payload that will be sent when "POST" method is used.
      replace: Dictionary of key->value pairs. In the recorded JSON output
               every "key" string will be replaced with its "value"
               counterpart. This way we can properly handle dynamically
               generated values (like hunts IDs) in the regression data.
    Raises:
      ValueError: if unsupported method argument is passed. Currently only
                  "GET", "POST", "DELETE" and "PATCH" are supported.
      RuntimeError: if request was handled by an unexpected API method (
                  every test is annotated with an "api_method" attribute
                  that points to the expected API method).
    """
        if self.use_api_v2:
            url = url.replace("/api/", "/api/v2/")

        parsed_url = urlparse.urlparse(url)
        request = utils.DataObject(method=method,
                                   scheme="http",
                                   path=parsed_url.path,
                                   environ={
                                       "SERVER_NAME": "foo.bar",
                                       "SERVER_PORT": 1234
                                   },
                                   user=self.token.username,
                                   body="")
        request.META = {"CONTENT_TYPE": "application/json"}

        if method == "GET":
            request.GET = dict(urlparse.parse_qsl(parsed_url.query))
        elif method in ["POST", "DELETE", "PATCH"]:
            # NOTE: this is a temporary trick. Payloads in regression tests
            # are using the API v1 (non-proto3) format. Here we're reparsing
            # them and serializing as proto3 JSON.
            # TODO(user): Make regression tests payload format-agnostic.
            # I.e. use protobuf and API client library to send requests.
            if self.use_api_v2 and payload:
                router_matcher = http_api.RouterMatcher()
                _, metadata, _ = router_matcher.MatchRouter(request)

                rdf_args = metadata.args_type()
                rdf_args.FromDict(payload)
                proto_args = metadata.args_type.protobuf()
                proto_args.ParseFromString(rdf_args.SerializeToString())

                request.body = json_format.MessageToJson(proto_args)
                payload = json.loads(request.body)
            else:
                request.body = json.dumps(payload or "")
        else:
            raise ValueError("Unsupported method: %s." % method)

        with self.NoAuthorizationChecks():
            http_response = http_api.RenderHttpResponse(request)

        api_method = http_response["X-API-Method"]
        if api_method != self.__class__.api_method:
            raise RuntimeError("Request was handled by an unexpected method. "
                               "Expected %s, got %s." %
                               (self.__class__.api_method, api_method))

        if hasattr(http_response, "streaming_content"):
            # We don't know the nature of response content, but we force it to be
            # unicode. It's a strategy that's good enough for testing purposes.
            content = utils.SmartUnicode("".join(
                http_response.streaming_content))
        else:
            content = http_response.content

        xssi_token = ")]}'\n"
        if content.startswith(xssi_token):
            content = content[len(xssi_token):]

        # replace the values of all tracebacks by <traceback content>
        regex = re.compile(r'"traceBack": "Traceback[^"\\]*(?:\\.[^"\\]*)*"',
                           re.DOTALL)
        content = regex.sub('"traceBack": "<traceback content>"', content)

        if replace:
            if hasattr(replace, "__call__"):
                replace = replace()

            # We reverse sort replacements by length to avoid cases when
            # replacements include each other and therefore order
            # of replacements affects the result.
            for substr in sorted(replace, key=len, reverse=True):
                repl = replace[substr]

                if hasattr(substr, "sub"):  # regex
                    content = substr.sub(repl, content)
                    url = substr.sub(repl, url)
                else:
                    content = content.replace(substr, repl)
                    url = url.replace(substr, repl)

        # We treat streaming content purely as strings and don't expect it to
        # contain JSON data.
        if hasattr(http_response, "streaming_content"):
            parsed_content = content
        else:
            parsed_content = json.loads(content)

        check_result = dict(api_method=api_method,
                            method=method,
                            url=url,
                            test_class=self.__class__.__name__,
                            response=parsed_content)

        if payload:
            check_result["request_payload"] = payload

        # Type stripping only makes sense for version 1 of the API.
        if not self.use_api_v2:
            stripped_content = api_value_renderers.StripTypeInfo(
                parsed_content)
            if parsed_content != stripped_content:
                check_result["type_stripped_response"] = stripped_content

        self.checks.append(check_result)
Esempio n. 5
0
def RenderApi(request):
    """Handler for the /api/ requests."""
    return http_api.RenderHttpResponse(request)
Esempio n. 6
0
    def Check(self, method, url, payload=None, replace=None):
        """Records output of a given url accessed with a given method.

    Args:
      method: HTTP method. May be "GET" or "POST".
      url: String repesenting an url.
      payload: JSON-able payload that will be sent when "POST" method is used.
      replace: Dictionary of key->value pairs. In the recorded JSON output
               every "key" string will be replaced with its "value"
               counterpart. This way we can properly handle dynamically
               generated values (like hunts IDs) in the regression data.
    Raises:
      ValueError: if unsupported method argument is passed. Currently only
                  "GET", "POST", "DELETE" and "PATCH" are supported.
    """
        parsed_url = urlparse.urlparse(url)
        request = utils.DataObject(method=method,
                                   scheme="http",
                                   path=parsed_url.path,
                                   environ={
                                       "SERVER_NAME": "foo.bar",
                                       "SERVER_PORT": 1234
                                   },
                                   user="******")
        request.META = {"CONTENT_TYPE": "application/json"}

        if method == "GET":
            request.GET = dict(urlparse.parse_qsl(parsed_url.query))
        elif method in ["POST", "DELETE", "PATCH"]:
            request.body = json.dumps(payload or "")
        else:
            raise ValueError("Unsupported method: %s." % method)

        with self.NoAuthorizationChecks():
            http_response = http_api.RenderHttpResponse(request)

        content = http_response.content

        xssi_token = ")]}'\n"
        if content.startswith(xssi_token):
            content = content[len(xssi_token):]

        # replace the values of all tracebacks by <traceback content>
        regex = re.compile(r'"traceBack": "Traceback[^"\\]*(?:\\.[^"\\]*)*"',
                           re.DOTALL)
        content = regex.sub('"traceBack": "<traceback content>"', content)

        if replace:
            if hasattr(replace, "__call__"):
                replace = replace()

            for substr, repl in replace.items():
                if hasattr(substr, "sub"):  # regex
                    content = substr.sub(repl, content)
                    url = substr.sub(repl, url)
                else:
                    content = content.replace(substr, repl)
                    url = url.replace(substr, repl)

        parsed_content = json.loads(content)
        check_result = dict(method=method,
                            url=url,
                            test_class=self.__class__.__name__,
                            response=parsed_content)

        if payload:
            check_result["request_payload"] = payload

        stripped_content = http_api.HttpRequestHandler.StripTypeInfo(
            parsed_content)
        if parsed_content != stripped_content:
            check_result["type_stripped_response"] = stripped_content

        self.checks.append(check_result)
Esempio n. 7
0
 def _RenderResponse(self, request):
     return http_api.RenderHttpResponse(request)