PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/server/transport.h

https://github.com/tstarling/hiphop-php
C Header | 475 lines | 246 code | 70 blank | 159 comment | 4 complexity | a578a0924277c722ce728bc09538037b MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 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. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_HTTP_SERVER_TRANSPORT_H_
  17. #define incl_HPHP_HTTP_SERVER_TRANSPORT_H_
  18. #include <string>
  19. #include <unordered_map>
  20. #include "hphp/util/compression.h"
  21. #include "hphp/util/functional.h"
  22. #include "hphp/runtime/base/types.h"
  23. #include "hphp/runtime/base/complex-types.h"
  24. #include "hphp/runtime/base/debuggable.h"
  25. #include "hphp/runtime/base/runtime-option.h"
  26. namespace HPHP {
  27. ///////////////////////////////////////////////////////////////////////////////
  28. /**
  29. * For storing headers and cookies.
  30. */
  31. template <typename V>
  32. using CaseInsenMap =
  33. std::unordered_map<std::string, V, string_hashi, string_eqstri>;
  34. using HeaderMap = CaseInsenMap<std::vector<std::string>>;
  35. using CookieMap = CaseInsenMap<std::string>;
  36. /**
  37. * A class defining an interface that request handler can use to query
  38. * transport related information.
  39. *
  40. * Note that one transport object is created for each request, and
  41. * one transport is ONLY accessed from one single thread.
  42. */
  43. class Transport : public IDebuggable {
  44. public:
  45. enum class Method {
  46. Unknown,
  47. GET,
  48. POST,
  49. HEAD,
  50. AUTO, // check GET parameter first, then POST
  51. };
  52. // TODO: add all status codes
  53. // (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
  54. enum class StatusCode {
  55. Unknown,
  56. // Success
  57. OK = 200,
  58. // Redirection
  59. MOVED_PERMANENTLY = 301,
  60. // Client Error
  61. BAD_REQUEST = 400,
  62. FORBIDDEN = 403,
  63. NOT_FOUND = 404,
  64. // Server Error
  65. INTERNAL_SERVER_ERROR = 500,
  66. SERVICE_UNAVAILABLE = 503,
  67. };
  68. enum class ThreadType {
  69. RequestThread,
  70. PageletThread,
  71. XboxThread,
  72. RpcThread,
  73. };
  74. public:
  75. Transport();
  76. virtual ~Transport();
  77. void onRequestStart(const timespec &queueTime);
  78. const timespec &getQueueTime() const { return m_queueTime; }
  79. const timespec &getWallTime() const { return m_wallTime; }
  80. const timespec &getCpuTime() const { return m_cpuTime; }
  81. const int64_t &getInstructions() const { return m_instructions; }
  82. const int64_t &getSleepTime() const { return m_sleepTime; }
  83. void incSleepTime(unsigned int seconds) { m_sleepTime += seconds; }
  84. const int64_t &getuSleepTime() const { return m_usleepTime; }
  85. void incuSleepTime(unsigned int useconds) { m_usleepTime += useconds; }
  86. const int64_t &getnSleepTimeS() const { return m_nsleepTimeS; }
  87. const int32_t &getnSleepTimeN() const { return m_nsleepTimeN; }
  88. void incnSleepTime(unsigned long int seconds, unsigned int nseconds) {
  89. m_nsleepTimeN += nseconds;
  90. m_nsleepTimeS += seconds + (m_nsleepTimeN / 1000000000);
  91. m_nsleepTimeN %= 1000000000;
  92. }
  93. ///////////////////////////////////////////////////////////////////////////
  94. // Functions sub-classes have to implement.
  95. /**
  96. * Request URI.
  97. */
  98. virtual const char *getUrl() = 0;
  99. virtual const char *getRemoteHost() = 0;
  100. virtual uint16_t getRemotePort() = 0;
  101. // The transport can override REMOTE_ADDR if it has one
  102. virtual const char *getRemoteAddr() { return ""; }
  103. // The transport can override the virtualhosts' docroot
  104. virtual const std::string getDocumentRoot() { return ""; }
  105. // The transport can say exactly what script to use
  106. virtual const std::string getPathTranslated() { return ""; }
  107. /**
  108. * Server Headers
  109. */
  110. virtual const char *getServerName() {
  111. return "";
  112. };
  113. virtual const char *getServerAddr() {
  114. return RuntimeOption::ServerPrimaryIP.c_str();
  115. };
  116. virtual uint16_t getServerPort() {
  117. return RuntimeOption::ServerPort;
  118. };
  119. virtual const char *getServerSoftware() {
  120. return "HPHP";
  121. };
  122. /**
  123. * POST request's data.
  124. */
  125. virtual const void *getPostData(int &size) = 0;
  126. virtual bool hasMorePostData() { return false; }
  127. virtual const void *getMorePostData(int &size) { size = 0; return nullptr; }
  128. virtual bool getFiles(std::string &files) { return false; }
  129. /**
  130. * Is this a GET, POST or anything?
  131. */
  132. virtual Method getMethod() = 0;
  133. virtual const char *getExtendedMethod() { return nullptr;}
  134. const char *getMethodName();
  135. /**
  136. * What version of HTTP was the request?
  137. */
  138. virtual std::string getHTTPVersion() const;
  139. /**
  140. * Get http request size.
  141. */
  142. virtual int getRequestSize() const;
  143. /**
  144. * Get request header(s).
  145. */
  146. virtual std::string getHeader(const char *name) = 0;
  147. virtual void getHeaders(HeaderMap &headers) = 0;
  148. virtual void getTransportParams(HeaderMap &serverParams) {};
  149. /**
  150. * Get/set response headers.
  151. */
  152. void addHeaderNoLock(const char *name, const char *value);
  153. void addHeader(const char *name, const char *value);
  154. void addHeader(const String& header);
  155. void replaceHeader(const char *name, const char *value);
  156. void replaceHeader(const String& header);
  157. void removeHeader(const char *name);
  158. void removeAllHeaders();
  159. void getResponseHeaders(HeaderMap &headers);
  160. std::string getFirstHeaderFile() const { return m_firstHeaderFile;}
  161. int getFirstHeaderLine() const { return m_firstHeaderLine;}
  162. /**
  163. * Content/MIME type related functions.
  164. */
  165. void setMimeType(const String& mimeType);
  166. String getMimeType();
  167. bool getUseDefaultContentType() { return m_sendContentType;}
  168. void setUseDefaultContentType(bool send) { m_sendContentType = send;}
  169. /**
  170. * Can we gzip response?
  171. */
  172. void enableCompression() { m_compression = true;}
  173. void disableCompression() { m_compression = false;}
  174. bool isCompressionEnabled() const {
  175. return m_compression && RuntimeOption::GzipCompressionLevel;
  176. }
  177. /**
  178. * Set cookie response header.
  179. */
  180. bool setCookie(const String& name, const String& value, int64_t expire = 0,
  181. const String& path = "", const String& domain = "", bool secure = false,
  182. bool httponly = false, bool encode_url = true);
  183. /**
  184. * Add/remove a response header.
  185. */
  186. virtual void addHeaderImpl(const char *name, const char *value) = 0;
  187. virtual void removeHeaderImpl(const char *name) = 0;
  188. /**
  189. * Add/remove a request header. Default is no-op, because not all transports
  190. * need to support incoming request header manipulations.
  191. */
  192. virtual void addRequestHeaderImpl(const char *name, const char *value) {}
  193. virtual void removeRequestHeaderImpl(const char *name) {}
  194. /**
  195. * Called when all sending should be done by this time point. Designed for
  196. * sending last chunk of response for chunked encoding.
  197. */
  198. void onSendEnd();
  199. /**
  200. * Send back a response with specified code.
  201. * Caller deletes data, callee must copy
  202. */
  203. virtual void sendImpl(const void *data, int size, int code,
  204. bool chunked) = 0;
  205. /**
  206. * Override to implement more send end logic.
  207. */
  208. virtual void onSendEndImpl() {}
  209. /**
  210. * Need this implementation to break keep-alive connections.
  211. */
  212. virtual bool isServerStopping() { return false;}
  213. ///////////////////////////////////////////////////////////////////////////
  214. // Pre-implemented utitlity functions.
  215. /**
  216. * We define a "server object" as the part of URL without domain name:
  217. *
  218. * http://facebook.com/foo?x=1 server object is "/foo?x=1"
  219. * http://facebook.com/foo/bar?x=1 server object is "/foo/bar?x=1"
  220. */
  221. virtual const char *getServerObject();
  222. /**
  223. * We define a "command" as the part of URL without parameters:
  224. *
  225. * /foo?x=1 command is "foo"
  226. * foo?x=1 command is "foo"
  227. * foo/bar?x=1 command is "foo/bar"
  228. * /foo/bar?x=1 command is "foo/bar"
  229. */
  230. std::string getCommand();
  231. /**
  232. * Whether a parameter exists. Normally this is not needed to know, unless
  233. * "null" is different from an empty string or 0.
  234. */
  235. bool paramExists(const char *name, Method method = Method::GET);
  236. /**
  237. * Get value of a parameter. Returns empty string is not present.
  238. */
  239. std::string getParam(const char *name, Method method = Method::GET);
  240. /**
  241. * Turn a string parameter into an integer.
  242. */
  243. int getIntParam(const char *name, Method method = Method::GET);
  244. /**
  245. * Turn a string parameter into a 64-bit number.
  246. */
  247. long long getInt64Param(const char *name, Method method = Method::GET);
  248. /**
  249. * Collect multiple string parameters with the same name into "values".
  250. *
  251. * /foo?x=1&x=2&x=3
  252. */
  253. void getArrayParam(const char *name, std::vector<std::string> &values,
  254. Method method = Method::GET);
  255. /**
  256. * Split a string parameter into multiple sub-strings.
  257. *
  258. * /foo?x=1:2:3
  259. */
  260. void getSplitParam(const char *name, std::vector<std::string> &values,
  261. char delimiter, Method method = Method::GET);
  262. /**
  263. * Test whether client accepts a certain encoding.
  264. */
  265. bool acceptEncoding(const char *encoding);
  266. /**
  267. * Test whether cookie header has the "name=".
  268. */
  269. bool cookieExists(const char *name);
  270. /**
  271. * Get value of cookie "name"
  272. */
  273. std::string getCookie(const std::string &name);
  274. /**
  275. * Test whether client is okay to accept compressed response.
  276. */
  277. bool decideCompression();
  278. /**
  279. * Sending back a response.
  280. */
  281. void setResponse(int code, const char *info) {
  282. assert(code != 500 || (info && *info)); // must have a reason for a 500
  283. m_responseCode = code;
  284. m_responseCodeInfo = info ? info : "";
  285. }
  286. const std::string &getResponseInfo() const { return m_responseCodeInfo; }
  287. bool headersSent() { return m_headerSent;}
  288. bool setHeaderCallback(const Variant& callback);
  289. private:
  290. void sendRawLocked(void *data, int size, int code = 200,
  291. bool compressed = false, bool chunked = false,
  292. const char *codeInfo = nullptr);
  293. public:
  294. virtual void sendRaw(void *data, int size, int code = 200,
  295. bool compressed = false, bool chunked = false,
  296. const char *codeInfo = nullptr);
  297. private:
  298. void sendStringLocked(const char *data, int code = 200,
  299. bool compressed = false, bool chunked = false,
  300. const char * codeInfo = nullptr) {
  301. sendRawLocked((void*)data, strlen(data), code, compressed, chunked,
  302. codeInfo);
  303. }
  304. public:
  305. void sendString(const char *data, int code = 200, bool compressed = false,
  306. bool chunked = false,
  307. const char * codeInfo = nullptr) {
  308. sendRaw((void*)data, strlen(data), code, compressed, chunked, codeInfo);
  309. }
  310. void sendString(const std::string &data, int code = 200,
  311. bool compressed = false, bool chunked = false,
  312. const char *codeInfo = nullptr) {
  313. sendRaw((void*)data.c_str(), data.length(), code, compressed, chunked,
  314. codeInfo);
  315. }
  316. void redirect(const char *location, int code, const char *info );
  317. // TODO: support rfc1867
  318. virtual bool isUploadedFile(const String& filename);
  319. int getResponseSize() const { return m_responseSize; }
  320. int getResponseCode() const { return m_responseCode; }
  321. int getResponseTotalSize() const { return m_responseTotalSize; }
  322. int getResponseSentSize() const { return m_responseSentSize; }
  323. int64_t getFlushTime() const { return m_flushTimeUs; }
  324. int getLastChunkSentSize();
  325. void getChunkSentSizes(Array &ret);
  326. void onFlushBegin(int totalSize) { m_responseTotalSize = totalSize; }
  327. void onFlushProgress(int writtenSize, int64_t delayUs);
  328. void onChunkedProgress(int writtenSize);
  329. void setThreadType(ThreadType type) { m_threadType = type;}
  330. ThreadType getThreadType() const { return m_threadType;}
  331. const char *getThreadTypeName() const;
  332. // implementing IDebuggable
  333. virtual void debuggerInfo(InfoVec &info);
  334. void setSSL() {m_isSSL = true;}
  335. bool isSSL() const {return m_isSSL;}
  336. protected:
  337. /**
  338. * Parameter parsing in this class is done by making just one copy of the
  339. * entire query (either URL or post data), then insert termintaing NULLs
  340. * at end of tokens (name and value), url decode in-place and then store
  341. * token's start char * addresses in ParamMaps. Therefore, this entire
  342. * process is very efficient without excessive string copying.
  343. */
  344. typedef hphp_hash_map<const char*, std::vector<const char*>,
  345. cstr_hash, eqstr> ParamMap;
  346. // timers
  347. timespec m_queueTime;
  348. timespec m_wallTime;
  349. timespec m_cpuTime;
  350. int64_t m_instructions;
  351. int64_t m_sleepTime;
  352. int64_t m_usleepTime;
  353. int64_t m_nsleepTimeS;
  354. int32_t m_nsleepTimeN;
  355. // input
  356. char *m_url;
  357. char *m_postData;
  358. bool m_postDataParsed;
  359. ParamMap m_getParams;
  360. ParamMap m_postParams;
  361. // output
  362. bool m_chunkedEncoding;
  363. bool m_headerSent;
  364. Variant m_headerCallback;
  365. bool m_headerCallbackDone; // used to prevent infinite loops
  366. int m_responseCode;
  367. std::string m_responseCodeInfo;
  368. HeaderMap m_responseHeaders;
  369. bool m_firstHeaderSet;
  370. std::string m_firstHeaderFile;
  371. int m_firstHeaderLine;
  372. CookieMap m_responseCookies;
  373. int m_responseSize;
  374. int m_responseTotalSize; // including added headers
  375. int m_responseSentSize;
  376. int64_t m_flushTimeUs;
  377. std::vector<int> m_chunksSentSizes;
  378. std::string m_mimeType;
  379. bool m_sendContentType;
  380. bool m_compression;
  381. StreamCompressor *m_compressor;
  382. bool m_isSSL;
  383. enum class CompressionDecision {
  384. NotDecidedYet,
  385. ShouldNot,
  386. Should,
  387. HasTo,
  388. };
  389. CompressionDecision m_compressionDecision;
  390. ThreadType m_threadType;
  391. // helpers
  392. void parseGetParams();
  393. void parsePostParams();
  394. static void parseQuery(char *query, ParamMap &params);
  395. static void urlUnescape(char *value);
  396. bool splitHeader(const String& header, String &name, const char *&value);
  397. String prepareResponse(const void *data, int size, bool &compressed,
  398. bool last);
  399. private:
  400. void prepareHeaders(bool compressed, bool chunked, const String &response,
  401. const String& orig_response);
  402. };
  403. ///////////////////////////////////////////////////////////////////////////////
  404. }
  405. #endif // incl_HPHP_HTTP_SERVER_TRANSPORT_H_