Arquivos
hhvm/hphp/runtime/server/transport.h
T
Edwin Smith c4e406b62f Move runtime/base/server to runtime/server
This is an incremental step towards moving it all the way
to hphp/server.  This flattens base but doesn't untangle
the server files from lib_hphp_runtime
2013-07-15 18:13:25 -07:00

433 linhas
13 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_HTTP_SERVER_TRANSPORT_H_
#define incl_HPHP_HTTP_SERVER_TRANSPORT_H_
#include "hphp/util/base.h"
#include "hphp/util/compression.h"
#include "hphp/runtime/base/types.h"
#include "hphp/runtime/base/complex_types.h"
#include "hphp/runtime/base/debuggable.h"
#include "hphp/runtime/base/runtime_option.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
/**
* For storing headers and cookies.
*/
typedef std::map<std::string, std::vector<std::string>, stdltistr> HeaderMap;
typedef std::map<std::string, std::string, stdltistr> CookieMap;
/**
* A class defining an interface that request handler can use to query
* transport related information.
*
* Note that one transport object is created for each request, and
* one transport is ONLY accessed from one single thread.
*/
class Transport : public IDebuggable {
public:
enum class Method {
Unknown,
GET,
POST,
HEAD,
AUTO, // check GET parameter first, then POST
};
// TODO: add all status codes
// (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
enum class StatusCode {
Unknown,
// Success
OK = 200,
// Redirection
MOVED_PERMANENTLY = 301,
// Client Error
BAD_REQUEST = 400,
FORBIDDEN = 403,
NOT_FOUND = 404,
// Server Error
INTERNAL_SERVER_ERROR = 500,
SERVICE_UNAVAILABLE = 503,
};
enum class ThreadType {
RequestThread,
PageletThread,
XboxThread,
RpcThread,
};
public:
Transport();
virtual ~Transport();
void onRequestStart(const timespec &queueTime);
const timespec &getQueueTime() const { return m_queueTime;}
const timespec &getWallTime() const { return m_wallTime;}
const timespec &getCpuTime() const { return m_cpuTime;}
const int64_t &getInstructions() const { return m_instructions;}
///////////////////////////////////////////////////////////////////////////
// Functions sub-classes have to implement.
/**
* Request URI.
*/
virtual const char *getUrl() = 0;
virtual const char *getRemoteHost() = 0;
virtual uint16_t getRemotePort() = 0;
/**
* POST request's data.
*/
virtual const void *getPostData(int &size) = 0;
virtual bool hasMorePostData() { return false; }
virtual const void *getMorePostData(int &size) { size = 0; return nullptr; }
virtual bool getFiles(std::string &files) { return false; }
/**
* Is this a GET, POST or anything?
*/
virtual Method getMethod() = 0;
virtual const char *getExtendedMethod() { return nullptr;}
const char *getMethodName();
/**
* What version of HTTP was the request?
*/
virtual std::string getHTTPVersion() const;
/**
* Get http request size.
*/
virtual int getRequestSize() const;
/**
* Get request header(s).
*/
virtual std::string getHeader(const char *name) = 0;
virtual void getHeaders(HeaderMap &headers) = 0;
/**
* Get/set response headers.
*/
void addHeaderNoLock(const char *name, const char *value);
void addHeader(const char *name, const char *value);
void addHeader(CStrRef header);
void replaceHeader(const char *name, const char *value);
void replaceHeader(CStrRef header);
void removeHeader(const char *name);
void removeAllHeaders();
void getResponseHeaders(HeaderMap &headers);
std::string getFirstHeaderFile() const { return m_firstHeaderFile;}
int getFirstHeaderLine() const { return m_firstHeaderLine;}
/**
* Content/MIME type related functions.
*/
void setMimeType(CStrRef mimeType);
String getMimeType();
const char *getDefaultContentType() { return "text/html";}
bool sendDefaultContentType() { return m_sendContentType;}
void setDefaultContentType(bool send) { m_sendContentType = send;}
/**
* Can we gzip response?
*/
void enableCompression() { m_compression = true;}
void disableCompression() { m_compression = false;}
bool isCompressionEnabled() const {
return m_compression && RuntimeOption::GzipCompressionLevel;
}
/**
* Set cookie response header.
*/
bool setCookie(CStrRef name, CStrRef value, int64_t expire = 0,
CStrRef path = "", CStrRef domain = "", bool secure = false,
bool httponly = false, bool encode_url = true);
/**
* Add/remove a response header.
*/
virtual void addHeaderImpl(const char *name, const char *value) = 0;
virtual void removeHeaderImpl(const char *name) = 0;
/**
* Add/remove a request header. Default is no-op, because not all transports
* need to support incoming request header manipulations.
*/
virtual void addRequestHeaderImpl(const char *name, const char *value) {}
virtual void removeRequestHeaderImpl(const char *name) {}
/**
* Called when all sending should be done by this time point. Designed for
* sending last chunk of response for chunked encoding.
*/
void onSendEnd();
/**
* Send back a response with specified code.
* Caller deletes data, callee must copy
*/
virtual void sendImpl(const void *data, int size, int code,
bool chunked) = 0;
/**
* Override to implement more send end logic.
*/
virtual void onSendEndImpl() {}
/**
* Need this implementation to break keep-alive connections.
*/
virtual bool isServerStopping() { return false;}
///////////////////////////////////////////////////////////////////////////
// Pre-implemented utitlity functions.
/**
* We define a "server object" as the part of URL without domain name:
*
* http://facebook.com/foo?x=1 server object is "/foo?x=1"
* http://facebook.com/foo/bar?x=1 server object is "/foo/bar?x=1"
*/
const char *getServerObject();
/**
* We define a "command" as the part of URL without parameters:
*
* /foo?x=1 command is "foo"
* foo?x=1 command is "foo"
* foo/bar?x=1 command is "foo/bar"
* /foo/bar?x=1 command is "foo/bar"
*/
std::string getCommand();
/**
* Whether a parameter exists. Normally this is not needed to know, unless
* "null" is different from an empty string or 0.
*/
bool paramExists(const char *name, Method method = Method::GET);
/**
* Get value of a parameter. Returns empty string is not present.
*/
std::string getParam(const char *name, Method method = Method::GET);
/**
* Turn a string parameter into an integer.
*/
int getIntParam(const char *name, Method method = Method::GET);
/**
* Turn a string parameter into a 64-bit number.
*/
long long getInt64Param(const char *name, Method method = Method::GET);
/**
* Collect multiple string parameters with the same name into "values".
*
* /foo?x=1&x=2&x=3
*/
void getArrayParam(const char *name, std::vector<std::string> &values,
Method method = Method::GET);
/**
* Split a string parameter into multiple sub-strings.
*
* /foo?x=1:2:3
*/
void getSplitParam(const char *name, std::vector<std::string> &values,
char delimiter, Method method = Method::GET);
/**
* Test whether client accepts a certain encoding.
*/
bool acceptEncoding(const char *encoding);
/**
* Test whether cookie header has the "name=".
*/
bool cookieExists(const char *name);
/**
* Get value of cookie "name"
*/
std::string getCookie(const std::string &name);
/**
* Test whether client is okay to accept compressed response.
*/
bool decideCompression();
/**
* Sending back a response.
*/
void setResponse(int code, const char *info) {
assert(code != 500 || (info && *info)); // must have a reason for a 500
m_responseCode = code;
m_responseCodeInfo = info ? info : "";
}
const std::string &getResponseInfo() const { return m_responseCodeInfo; }
bool headersSent() { return m_headerSent;}
bool setHeaderCallback(CVarRef callback);
private:
void sendRawLocked(void *data, int size, int code = 200,
bool compressed = false, bool chunked = false,
const char *codeInfo = nullptr);
public:
virtual void sendRaw(void *data, int size, int code = 200,
bool compressed = false, bool chunked = false,
const char *codeInfo = nullptr);
private:
void sendStringLocked(const char *data, int code = 200,
bool compressed = false, bool chunked = false,
const char * codeInfo = nullptr) {
sendRawLocked((void*)data, strlen(data), code, compressed, chunked,
codeInfo);
}
public:
void sendString(const char *data, int code = 200, bool compressed = false,
bool chunked = false,
const char * codeInfo = nullptr) {
sendRaw((void*)data, strlen(data), code, compressed, chunked, codeInfo);
}
void sendString(const std::string &data, int code = 200,
bool compressed = false, bool chunked = false,
const char *codeInfo = nullptr) {
sendRaw((void*)data.c_str(), data.length(), code, compressed, chunked,
codeInfo);
}
void redirect(const char *location, int code, const char *info );
// TODO: support rfc1867
virtual bool isUploadedFile(CStrRef filename);
virtual bool moveUploadedFile(CStrRef filename, CStrRef destination);
int getResponseSize() const { return m_responseSize; }
int getResponseCode() const { return m_responseCode; }
int getResponseTotalSize() const { return m_responseTotalSize; }
int getResponseSentSize() const { return m_responseSentSize; }
int64_t getFlushTime() const { return m_flushTimeUs; }
int getLastChunkSentSize();
void getChunkSentSizes(Array &ret);
void onFlushBegin(int totalSize) { m_responseTotalSize = totalSize; }
void onFlushProgress(int writtenSize, int64_t delayUs);
void onChunkedProgress(int writtenSize);
void setThreadType(ThreadType type) { m_threadType = type;}
ThreadType getThreadType() const { return m_threadType;}
const char *getThreadTypeName() const;
// implementing IDebuggable
virtual void debuggerInfo(InfoVec &info);
void setSSL() {m_isSSL = true;}
bool isSSL() const {return m_isSSL;}
protected:
/**
* Parameter parsing in this class is done by making just one copy of the
* entire query (either URL or post data), then insert termintaing NULLs
* at end of tokens (name and value), url decode in-place and then store
* token's start char * addresses in ParamMaps. Therefore, this entire
* process is very efficient without excessive string copying.
*/
typedef hphp_hash_map<const char *, std::vector<const char *>,
hphp_hash<const char *>, eqstr> ParamMap;
// timers
timespec m_queueTime;
timespec m_wallTime;
timespec m_cpuTime;
int64_t m_instructions;
// input
char *m_url;
char *m_postData;
bool m_postDataParsed;
ParamMap m_getParams;
ParamMap m_postParams;
// output
bool m_chunkedEncoding;
bool m_headerSent;
Variant m_headerCallback;
bool m_headerCallbackDone; // used to prevent infinite loops
int m_responseCode;
std::string m_responseCodeInfo;
HeaderMap m_responseHeaders;
bool m_firstHeaderSet;
std::string m_firstHeaderFile;
int m_firstHeaderLine;
CookieMap m_responseCookies;
int m_responseSize;
int m_responseTotalSize; // including added headers
int m_responseSentSize;
int64_t m_flushTimeUs;
std::vector<int> m_chunksSentSizes;
std::string m_mimeType;
bool m_sendContentType;
bool m_compression;
StreamCompressor *m_compressor;
bool m_isSSL;
enum class CompressionDecision {
NotDecidedYet,
ShouldNot,
Should,
HasTo,
};
CompressionDecision m_compressionDecision;
ThreadType m_threadType;
// helpers
void parseGetParams();
void parsePostParams();
static void parseQuery(char *query, ParamMap &params);
static void urlUnescape(char *value);
bool splitHeader(CStrRef header, String &name, const char *&value);
String prepareResponse(const void *data, int size, bool &compressed,
bool last);
bool moveUploadedFileHelper(CStrRef filename, CStrRef destination);
private:
void prepareHeaders(bool compressed, bool chunked, const String &response,
const String& orig_response);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_HTTP_SERVER_TRANSPORT_H_