Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: third_party/google-endpoints/endpoints/api_request.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2016 Google Inc. All Rights Reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """Cloud Endpoints API request-related data and functions."""
16
17 from __future__ import with_statement
18
19 # pylint: disable=g-bad-name
20 import copy
21 import json
22 import logging
23 import urllib
24 import urlparse
25 import zlib
26
27 import util
28
29
30 class ApiRequest(object):
31 """Simple data object representing an API request.
32
33 Parses the request from environment variables into convenient pieces
34 and stores them as members.
35 """
36 def __init__(self, environ, base_paths=None):
37 """Constructor.
38
39 Args:
40 environ: An environ dict for the request as defined in PEP-333.
41
42 Raises:
43 ValueError: If the path for the request is invalid.
44 """
45 self.headers = util.get_headers_from_environ(environ)
46 self.http_method = environ['REQUEST_METHOD']
47 self.url_scheme = environ['wsgi.url_scheme']
48 self.server = environ['SERVER_NAME']
49 self.port = environ['SERVER_PORT']
50 self.path = environ['PATH_INFO']
51 self.query = environ.get('QUERY_STRING')
52 self.body = environ['wsgi.input'].read()
53 if self.body and self.headers.get('CONTENT-ENCODING') == 'gzip':
54 # Increasing wbits to 16 + MAX_WBITS is necessary to be able to decode
55 # gzipped content (as opposed to zlib-encoded content).
56 # If there's an error in the decompression, it could be due to another
57 # part of the serving chain that already decompressed it without clearing
58 # the header. If so, just ignore it and continue.
59 try:
60 self.body = zlib.decompress(self.body, 16 + zlib.MAX_WBITS)
61 except zlib.error:
62 pass
63 self.source_ip = environ.get('REMOTE_ADDR')
64 self.relative_url = self._reconstruct_relative_url(environ)
65
66 if not base_paths:
67 base_paths = set()
68 elif isinstance(base_paths, list):
69 base_paths = set(base_paths)
70
71 # Find a base_path in the path
72 for base_path in base_paths:
73 if self.path.startswith(base_path):
74 self.path = self.path[len(base_path):]
75 self.base_path = base_path
76 break
77 else:
78 raise ValueError('Invalid request path: %s' % self.path)
79
80 if self.query:
81 self.parameters = urlparse.parse_qs(self.query, keep_blank_values=True)
82 else:
83 self.parameters = {}
84 self.body_json = self._process_req_body(self.body) if self.body else {}
85 self.request_id = None
86
87 # Check if it's a batch request. We'll only handle single-element batch
88 # requests on the dev server (and we need to handle them because that's
89 # what RPC and JS calls typically show up as). Pull the request out of the
90 # list and record the fact that we're processing a batch.
91 if isinstance(self.body_json, list):
92 if len(self.body_json) != 1:
93 logging.warning('Batch requests with more than 1 element aren\'t '
94 'supported in devappserver2. Only the first element '
95 'will be handled. Found %d elements.',
96 len(self.body_json))
97 else:
98 logging.info('Converting batch request to single request.')
99 self.body_json = self.body_json[0]
100 self.body = json.dumps(self.body_json)
101 self._is_batch = True
102 else:
103 self._is_batch = False
104
105 def _process_req_body(self, body):
106 """Process the body of the HTTP request.
107
108 If the body is valid JSON, return the JSON as a dict.
109 Else, convert the key=value format to a dict and return that.
110
111 Args:
112 body: The body of the HTTP request.
113 """
114 try:
115 return json.loads(body)
116 except ValueError:
117 return urlparse.parse_qs(body, keep_blank_values=True)
118
119 def _reconstruct_relative_url(self, environ):
120 """Reconstruct the relative URL of this request.
121
122 This is based on the URL reconstruction code in Python PEP 333:
123 http://www.python.org/dev/peps/pep-0333/#url-reconstruction. Rebuild the
124 URL from the pieces available in the environment.
125
126 Args:
127 environ: An environ dict for the request as defined in PEP-333.
128
129 Returns:
130 The portion of the URL from the request after the server and port.
131 """
132 url = urllib.quote(environ.get('SCRIPT_NAME', ''))
133 url += urllib.quote(environ.get('PATH_INFO', ''))
134 if environ.get('QUERY_STRING'):
135 url += '?' + environ['QUERY_STRING']
136 return url
137
138 def copy(self):
139 return copy.deepcopy(self)
140
141 def is_rpc(self):
142 # Google's JsonRPC protocol creates a handler at /rpc for any Cloud
143 # Endpoints API, with api name, version, and method name being in the
144 # body of the request.
145 # If the request is sent to /rpc, we will treat it as JsonRPC.
146 # The client libraries for iOS's Objective C use RPC and not the REST
147 # versions of the API.
148 return self.path == 'rpc'
149
150 def is_batch(self):
151 return self._is_batch
OLDNEW
« no previous file with comments | « third_party/google-endpoints/endpoints/api_exceptions.py ('k') | third_party/google-endpoints/endpoints/apiserving.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698