Create dedicate crate for php_escaping.rs
[hiphop-php.git] / hphp / runtime / server / transport.h
blob4e868746486cc2eb683b70ffab6c1c58ec403bb0
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_HTTP_SERVER_TRANSPORT_H_
18 #define incl_HPHP_HTTP_SERVER_TRANSPORT_H_
20 #include "hphp/runtime/base/debuggable.h"
21 #include "hphp/runtime/base/request-tracing.h"
22 #include "hphp/runtime/base/runtime-option.h"
23 #include "hphp/runtime/base/type-string.h"
24 #include "hphp/util/functional.h"
25 #include "hphp/util/gzip.h"
26 #include "hphp/util/string-holder.h"
28 #include <list>
29 #include <string>
30 #include <unordered_map>
31 #include <utility>
32 #include <vector>
34 namespace HPHP {
35 ///////////////////////////////////////////////////////////////////////////////
37 struct Array;
38 struct Variant;
39 struct ResponseCompressorManager;
40 struct StructuredLogEntry;
42 /**
43 * For storing headers and cookies.
45 template <typename V>
46 using CaseInsenMap =
47 std::unordered_map<std::string, V, string_hashi, string_eqstri>;
49 using HeaderMap = CaseInsenMap<std::vector<std::string>>;
50 using CookieList = std::vector<std::pair<std::string, std::string>>;
52 struct ITransportHeaders {
53 /* Request header methods */
54 virtual const char *getUrl() = 0;
55 virtual std::string getCommand() = 0; // URL with params stripped
56 virtual std::string getHeader(const char *name) = 0;
57 virtual const HeaderMap& getHeaders() = 0;
59 /* Response header methods */
60 virtual void addHeaderNoLock(const char *name, const char *value) = 0;
61 virtual void addHeader(const char *name, const char *value) = 0;
62 virtual void addHeader(const String& header) = 0;
63 virtual void replaceHeader(const char *name, const char *value) = 0;
64 virtual void replaceHeader(const String& header) = 0;
65 virtual void removeHeader(const char *name) = 0;
66 virtual void removeAllHeaders() = 0;
67 virtual void getResponseHeaders(HeaderMap& headers) = 0;
70 /**
71 * A class defining an interface that request handler can use to query
72 * transport related information.
74 * Note that one transport object is created for each request, and
75 * one transport is ONLY accessed from one single thread.
77 struct Transport : IDebuggable, ITransportHeaders {
78 enum class Method {
79 Unknown,
81 GET,
82 POST,
83 HEAD,
84 AUTO, // check GET parameter first, then POST
87 // TODO: add all status codes
88 // (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
89 enum class StatusCode {
90 Unknown,
92 // Success
93 OK = 200,
95 // Redirection
96 MOVED_PERMANENTLY = 301,
98 // Client Error
99 BAD_REQUEST = 400,
100 FORBIDDEN = 403,
101 NOT_FOUND = 404,
103 // Server Error
104 INTERNAL_SERVER_ERROR = 500,
105 SERVICE_UNAVAILABLE = 503,
108 enum class ThreadType {
109 RequestThread,
110 PageletThread,
111 XboxThread,
112 RpcThread,
115 public:
116 Transport();
117 ~Transport() override;
119 void onRequestStart(const timespec &queueTime);
120 const timespec &getQueueTime() const { return m_queueTime; }
121 const timespec &getWallTime() const { return m_wallTime; }
122 const timespec &getCpuTime() const { return m_cpuTime; }
123 const int64_t &getInstructions() const { return m_instructions; }
124 const int64_t &getSleepTime() const { return m_sleepTime; }
125 void incSleepTime(unsigned int seconds) { m_sleepTime += seconds; }
126 const int64_t &getuSleepTime() const { return m_usleepTime; }
127 void incuSleepTime(unsigned int useconds) { m_usleepTime += useconds; }
128 const int64_t &getnSleepTimeS() const { return m_nsleepTimeS; }
129 const int32_t &getnSleepTimeN() const { return m_nsleepTimeN; }
130 void incnSleepTime(unsigned long int seconds, unsigned int nseconds) {
131 m_nsleepTimeN += nseconds;
132 m_nsleepTimeS += seconds + (m_nsleepTimeN / 1000000000);
133 m_nsleepTimeN %= 1000000000;
136 void forceInitRequestTrace();
137 rqtrace::Trace* getRequestTrace() { return m_requestTrace.get_pointer(); }
138 StructuredLogEntry* createStructuredLogEntry();
139 StructuredLogEntry* getStructuredLogEntry();
140 void resetStructuredLogEntry();
142 ///////////////////////////////////////////////////////////////////////////
143 // Functions sub-classes have to implement.
146 * Request URI.
148 virtual const char *getUrl() = 0;
149 virtual const char *getRemoteHost() = 0;
150 virtual uint16_t getRemotePort() = 0;
151 // The transport can override REMOTE_ADDR if it has one
152 virtual const char *getRemoteAddr() { return ""; }
153 // The transport can override the virtualhosts' docroot
154 virtual const std::string getDocumentRoot() { return ""; }
155 // The transport can say exactly what script to use
156 virtual const std::string getScriptFilename() { return ""; }
157 virtual const std::string getPathTranslated() { return ""; }
158 virtual const std::string getPathInfo() { return ""; }
159 virtual bool isPathInfoSet() {return false; }
162 * Server Headers
164 virtual const char *getServerName() {
165 return "";
167 virtual const std::string& getServerAddr() {
168 auto const& ipv4 = RuntimeOption::GetServerPrimaryIPv4();
169 return ipv4.empty() ? RuntimeOption::GetServerPrimaryIPv6() : ipv4;
171 virtual uint16_t getServerPort() {
172 return RuntimeOption::ServerPort;
174 virtual const char *getServerSoftware() {
175 return "HPHP";
179 * POST request's data.
181 virtual const void *getPostData(size_t &size) = 0;
182 virtual bool hasMorePostData() { return false; }
183 virtual const void *getMorePostData(size_t &size) { size = 0;return nullptr; }
184 virtual bool getFiles(std::string& /*files*/) { return false; }
186 * Is this a GET, POST or anything?
188 virtual Method getMethod() = 0;
189 virtual const char *getExtendedMethod() { return nullptr;}
190 const char *getMethodName();
193 * What version of HTTP was the request?
195 virtual std::string getHTTPVersion() const;
198 * Get http request size.
200 virtual size_t getRequestSize() const;
203 * Get transport params.
205 virtual void getTransportParams(HeaderMap& /*serverParams*/){};
208 * Get a description of the type of transport.
210 virtual String describe() const = 0;
213 * Get/set response headers.
215 void addHeaderNoLock(const char *name, const char *value) override;
216 void addHeader(const char *name, const char *value) override;
217 void addHeader(const String& header) override;
218 void replaceHeader(const char *name, const char *value) override;
219 void replaceHeader(const String& header) override;
220 void removeHeader(const char *name) override;
221 void removeAllHeaders() override;
222 void getResponseHeaders(HeaderMap &headers) override;
223 std::string getFirstHeaderFile() const { return m_firstHeaderFile;}
224 int getFirstHeaderLine() const { return m_firstHeaderLine;}
227 * Content/MIME type related functions.
229 void setMimeType(const String& mimeType);
230 String getMimeType();
231 bool getUseDefaultContentType() { return m_sendContentType;}
232 void setUseDefaultContentType(bool send) { m_sendContentType = send;}
235 * Can we compress response?
237 void enableCompression();
238 void disableCompression();
239 bool isCompressionEnabled();
242 * Set cookie response header.
244 bool setCookie(const String& name, const String& value, int64_t expire = 0,
245 const String& path = "", const String& domain = "",
246 bool secure = false, bool httponly = false,
247 bool encode_url = true);
250 * Add/remove a response header.
252 virtual void addHeaderImpl(const char *name, const char *value) = 0;
253 virtual void removeHeaderImpl(const char *name) = 0;
256 * Add/remove a request header. Default is no-op, because not all transports
257 * need to support incoming request header manipulations.
259 virtual void
260 addRequestHeaderImpl(const char* /*name*/, const char* /*value*/) {}
261 virtual void removeRequestHeaderImpl(const char* /*name*/) {}
264 * Called when all sending should be done by this time point. Designed for
265 * sending last chunk of response for chunked encoding.
267 void onSendEnd();
270 * Send back a response with specified code.
271 * Caller deletes data, callee must copy
273 virtual void sendImpl(const void *data, int size, int code,
274 bool chunked, bool eom) = 0;
277 * Override to implement more send end logic.
279 virtual void onSendEndImpl() {}
282 * Returns true if this transport supports server pushed resources
284 virtual bool supportsServerPush() { return false; }
287 * Attempt to push the resource identified by host/path on this transport
289 * @param priority (3 bit priority, 0 = highest, 7 = lowest),
290 * @param promiseHeaders HTTP request headers for this resource
291 * (for PUSH_PROMISE)
292 * @param responseHeaders HTTP response headers for this resource
293 * @param body body bytes (optional)
294 * @param size length of @p body or 0
295 * @param eom true if no more body bytes are expected
297 * @return an ID that can be passed to pushResourceBody if more body
298 * is being streamed later. 0 indicates that the push failed
299 * immediately.
301 virtual int64_t
302 pushResource(const char* /*host*/, const char* /*path*/, uint8_t /*priority*/,
303 const Array& /*promiseHeaders*/,
304 const Array& /*responseHeaders*/, const void* /*data*/,
305 int /*size*/, bool /*eom*/) {
306 return 0;
310 * Stream body and/or EOM marker for a pushed resource
312 * @param id ID returned by pushResource
313 * @param data body bytes (optional if eom is true)
314 * @param size length of @p body
315 * @param eom true if no more body bytes are expected
317 virtual void pushResourceBody(int64_t /*id*/, const void* /*data*/,
318 int /*size*/, bool /*eom*/) {}
321 * Need this implementation to break keep-alive connections.
323 virtual bool isServerStopping() { return false;}
325 ///////////////////////////////////////////////////////////////////////////
326 // Pre-implemented utitlity functions.
329 * We define a "server object" as the part of URL without domain name:
331 * http://facebook.com/foo?x=1 server object is "/foo?x=1"
332 * http://facebook.com/foo/bar?x=1 server object is "/foo/bar?x=1"
334 virtual const char *getServerObject();
337 * We define a "command" as the part of URL without parameters:
339 * /foo?x=1 command is "foo"
340 * foo?x=1 command is "foo"
341 * foo/bar?x=1 command is "foo/bar"
342 * /foo/bar?x=1 command is "foo/bar"
344 std::string getCommand();
347 * Whether a parameter exists. Normally this is not needed to know, unless
348 * "null" is different from an empty string or 0.
350 bool paramExists(const char *name, Method method = Method::GET);
353 * Get value of a parameter. Returns empty string is not present.
355 std::string getParam(const char *name, Method method = Method::GET);
358 * Turn a string parameter into an integer.
360 int getIntParam(const char *name, Method method = Method::GET);
363 * Turn a string parameter into a 64-bit number.
365 long long getInt64Param(const char *name, Method method = Method::GET);
368 * Collect multiple string parameters with the same name into "values".
370 * /foo?x=1&x=2&x=3
372 void getArrayParam(const char *name, std::vector<std::string> &values,
373 Method method = Method::GET);
376 * Split a string parameter into multiple sub-strings.
378 * /foo?x=1:2:3
380 void getSplitParam(const char *name, std::vector<std::string> &values,
381 char delimiter, Method method = Method::GET);
384 * Test whether client accepts a certain encoding.
386 bool acceptEncoding(const char *encoding);
389 * Test whether cookie header has the "name=".
391 bool cookieExists(const char *name);
394 * Get value of cookie "name"
396 std::string getCookie(const std::string &name);
399 * Sending back a response.
401 void setResponse(int code, const char *info = nullptr);
402 const std::string &getResponseInfo() const { return m_responseCodeInfo; }
403 bool headersSent() { return m_headerSent;}
404 void sendRaw(const char *data, int size, int code = 200,
405 bool precompressed = false, bool chunked = false,
406 const char *codeInfo = nullptr);
407 private:
408 void sendRawInternal(const char *data, int size, int code = 200,
409 bool precompressed = false,
410 const char *codeInfo = nullptr);
411 public:
412 void sendString(const char *data, int code = 200, bool precompressed = false,
413 bool chunked = false,
414 const char * codeInfo = nullptr) {
415 sendRaw(data, strlen(data), code, precompressed, chunked, codeInfo);
417 void sendString(const std::string &data, int code = 200,
418 bool precompressed = false, bool chunked = false,
419 const char *codeInfo = nullptr) {
420 sendRaw(data.c_str(), data.length(), code, precompressed, chunked,
421 codeInfo);
423 void redirect(const char *location, int code, const char *info = nullptr);
425 // TODO: support rfc1867
426 virtual bool isUploadedFile(const String& filename);
428 int getResponseSize() const { return m_responseSize; }
429 int getResponseCode() const { return m_responseCode; }
431 int getResponseTotalSize() const { return m_responseTotalSize; }
432 int getResponseSentSize() const { return m_responseSentSize; }
433 int64_t getFlushTime() const { return m_flushTimeUs; }
434 int getLastChunkSentSize();
435 void getChunkSentSizes(Array &ret);
436 void onFlushBegin(int totalSize) { m_responseTotalSize = totalSize; }
437 void onFlushProgress(int writtenSize, int64_t delayUs);
438 void onChunkedProgress(int writtenSize);
440 void setThreadType(ThreadType type) { m_threadType = type;}
441 ThreadType getThreadType() const { return m_threadType;}
442 const char *getThreadTypeName() const;
444 // implementing IDebuggable
445 void debuggerInfo(InfoVec& info) override;
447 void setSSL() {m_isSSL = true;}
448 bool isSSL() const {return m_isSSL;}
451 * Request to adjust the maximum number of threads on the server.
453 virtual void trySetMaxThreadCount(int max) {}
455 protected:
457 * Parameter parsing in this class is done by making just one copy of the
458 * entire query (either URL or post data), then insert termintaing NULLs
459 * at end of tokens (name and value), url decode in-place and then store
460 * token's start char * addresses in ParamMaps. Therefore, this entire
461 * process is very efficient without excessive string copying.
463 using ParamMap = hphp_hash_map<const char*, std::vector<const char*>,
464 cstr_hash, eqstr>;
466 // timers and other perf data
467 timespec m_queueTime;
468 timespec m_wallTime;
469 timespec m_cpuTime;
471 int64_t m_instructions;
473 int64_t m_sleepTime;
474 int64_t m_usleepTime;
475 int64_t m_nsleepTimeS;
476 int32_t m_nsleepTimeN;
478 std::unique_ptr<StructuredLogEntry> m_structLogEntry;
480 // input
481 char *m_url;
482 char *m_postData;
483 bool m_postDataParsed;
484 ParamMap m_getParams;
485 ParamMap m_postParams;
487 // output
488 bool m_chunkedEncoding;
489 bool m_headerSent;
490 int m_responseCode;
491 std::string m_responseCodeInfo;
492 HeaderMap m_responseHeaders;
493 bool m_firstHeaderSet;
494 std::string m_firstHeaderFile;
495 int m_firstHeaderLine;
496 CookieList m_responseCookiesList;
497 int m_responseSize;
498 int m_responseTotalSize; // including added headers
499 int m_responseSentSize;
500 int64_t m_flushTimeUs;
501 bool m_sendEnded;
503 std::vector<int> m_chunksSentSizes;
505 std::string m_mimeType;
506 bool m_sendContentType;
508 std::unique_ptr<ResponseCompressorManager> m_compressor;
510 bool m_isSSL;
512 ThreadType m_threadType;
514 folly::Optional<rqtrace::Trace> m_requestTrace;
516 // helpers
517 void parseGetParams();
518 void parsePostParams();
519 static void parseQuery(char *query, ParamMap &params);
520 static void urlUnescape(char *value);
521 bool splitHeader(const String& header, String &name, const char *&value);
522 std::list<std::string> getCookieLines();
524 ResponseCompressorManager& getCompressor();
527 private:
528 StringHolder compressResponse(const char *data, int size, bool last);
529 void prepareHeaders(bool precompressed, bool chunked,
530 const StringHolder &response, const StringHolder& orig_response);
533 ///////////////////////////////////////////////////////////////////////////////
536 #endif // incl_HPHP_HTTP_SERVER_TRANSPORT_H_