1 // 2 // Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 3 // Free Software Foundation, Inc. 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 // 19 20 #ifndef GNASH_LIBNET_HTTP_H 21 #define GNASH_LIBNET_HTTP_H 22 23 #include <string> 24 #include <map> 25 #include <vector> 26 #include <sstream> 27 28 #ifdef HAVE_CONFIG_H 29 #include "gnashconfig.h" 30 #endif 31 32 #include "amf.h" 33 #include "cque.h" 34 #include "rtmp.h" 35 //#include "handler.h" 36 #include "network.h" 37 #include "buffer.h" 38 #include "diskstream.h" 39 40 namespace gnash 41 { 42 43 class DSOEXPORT HTTP : public gnash::Network 44 { 45 public: 46 // as defined by the W3: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 47 typedef enum { 48 // 1xx: Informational - Request received, continuing process 49 CONTINUE = 100, 50 SWITCHPROTOCOLS = 101, 51 // 2xx: Success - The action was successfully received, 52 // understood, and accepted 53 OK = 200, 54 CREATED = 201, 55 ACCEPTED = 202, 56 NON_AUTHORITATIVE = 203, 57 NO_CONTENT = 204, 58 RESET_CONTENT = 205, 59 PARTIAL_CONTENT = 206, 60 // 3xx: Redirection - Further action must be taken in order to 61 // complete the request 62 MULTIPLE_CHOICES = 300, 63 MOVED_PERMANENTLY = 301, 64 FOUND = 302, 65 SEE_OTHER = 303, 66 NOT_MODIFIED = 304, 67 USE_PROXY = 305, 68 TEMPORARY_REDIRECT = 307, 69 // 4xx: Client Error - The request contains bad syntax or 70 // cannot be fulfilled 71 BAD_REQUEST = 400, 72 UNAUTHORIZED = 401, 73 PAYMENT_REQUIRED = 402, 74 FORBIDDEN = 403, 75 NOT_FOUND = 404, 76 METHOD_NOT_ALLOWED = 405, 77 NOT_ACCEPTABLE = 406, 78 PROXY_AUTHENTICATION_REQUIRED = 407, 79 REQUEST_TIMEOUT = 408, 80 CONFLICT = 409, 81 GONE = 410, 82 LENGTH_REQUIRED = 411, 83 PRECONDITION_FAILED = 412, 84 REQUEST_ENTITY_TOO_LARGE = 413, 85 REQUEST_URI_TOO_LARGE = 414, 86 UNSUPPORTED_MEDIA_TYPE = 415, 87 REQUESTED_RANGE_NOT_SATISFIABLE = 416, 88 EXPECTATION_FAILED = 417, 89 // 5xx: Server Error - The server failed to fulfill an apparently valid request 90 INTERNAL_SERVER_ERROR = 500, 91 NOT_IMPLEMENTED = 501, 92 BAD_GATEWAY = 502, 93 SERVICE_UNAVAILABLE = 503, 94 GATEWAY_TIMEOUT = 504, 95 HTTP_VERSION_NOT_SUPPORTED = 505, 96 // Gnash/Cygnal extensions for internal use 97 LIFE_IS_GOOD = 1234, 98 CLOSEPIPE = 1235 99 } http_status_e; 100 typedef enum { 101 HTTP_NONE, 102 HTTP_OPTIONS, 103 HTTP_GET, 104 HTTP_HEAD, 105 HTTP_POST, 106 HTTP_PUT, 107 HTTP_DELETE, 108 HTTP_TRACE, 109 HTTP_CONNECT, 110 HTTP_RESPONSE // unique to gnash 111 } http_method_e; 112 typedef enum { 113 OPEN, 114 SEND, 115 IDLE, 116 CLOSE 117 } rtmpt_cmd_e; 118 // A response from an FTTP request has a code an an error message 119 typedef struct { 120 http_status_e code; 121 std::string msg; 122 } http_response_t; 123 typedef struct { 124 int major; 125 int minor; 126 } http_version_t; 127 HTTP(); 128 // HTTP(Handler *hand); 129 ~HTTP(); 130 131 // Check the Header fields to make sure they're valid values. 132 bool checkRequestFields(cygnal::Buffer &buf); 133 bool checkEntityFields(cygnal::Buffer &buf); 134 bool checkGeneralFields(cygnal::Buffer &buf); 135 136 // // Parse an Echo Request message coming from the Red5 echo_test. parseEchoRequest(cygnal::Buffer & buf)137 std::vector<std::shared_ptr<cygnal::Element > > parseEchoRequest(cygnal::Buffer &buf) { return parseEchoRequest(buf.reference(), buf.size()); }; 138 std::vector<std::shared_ptr<cygnal::Element > > parseEchoRequest(std::uint8_t *buf, size_t size); 139 140 // Convert the Content-Length field to a number we can use 141 size_t getContentLength(); 142 143 // process all the header fields in the Buffer, storing them internally 144 // in _fields. The address returned is the address where the Content data 145 // starts, and is "Content-Length" bytes long, of "Content-Type" data. 146 std::uint8_t *processHeaderFields(cygnal::Buffer *buf); 147 148 // Get the field for header 'name' that was stored by processHeaderFields() getField(const std::string & name)149 std::string &getField(const std::string &name) { return _fields[name]; }; NumOfFields()150 size_t NumOfFields() { return _fields.size(); }; clearFields()151 void clearFields() { _fields.clear(); }; getFields()152 std::map<std::string, std::string> &getFields() { return _fields; }; 153 154 // Get an array of values for header field 'name'. 155 std::shared_ptr<std::vector<std::string> > getFieldItem(const std::string &name); 156 157 // Client side parsing of response message codes 158 std::shared_ptr<http_response_t> parseStatus(const std::string &line); 159 160 // Handle the response for the request. 161 std::shared_ptr<cygnal::Buffer> formatServerReply(http_status_e code); 162 cygnal::Buffer &formatGetReply(DiskStream::filetype_e type, size_t size, http_status_e code); 163 cygnal::Buffer &formatGetReply(size_t size, http_status_e code); 164 cygnal::Buffer &formatGetReply(http_status_e code); 165 cygnal::Buffer &formatPostReply(rtmpt_cmd_e code); 166 167 // Make copies of ourself 168 HTTP &operator = (HTTP &obj); 169 170 /// @note These methods add data to the fields in the HTTP header. 171 /// \brief clear the data in the stored header 172 bool clearHeader(); 173 174 /// \brief Start constructing a new HTTP header. 175 /// As it's hard to predict how much storage to allocate, 176 /// all of these methods for formatting HTTP header 177 /// fields store the header while adding data to it. It 178 /// requires another function to actually send the data. 179 bool startHeader(); 180 181 /// \brief Format the common header fields that need no other processing. 182 /// Most of these fields are purely ASCII based, and so 183 /// chare a common constructor. A few require formatting 184 /// of numerical data into string data, so they can't use 185 /// the common form. 186 cygnal::Buffer &formatCommon(const std::string &data); 187 188 cygnal::Buffer &formatHeader(DiskStream::filetype_e type, size_t filesize, 189 http_status_e code); 190 cygnal::Buffer &formatHeader(size_t filesize, http_status_e type); 191 cygnal::Buffer &formatHeader(http_status_e type); 192 cygnal::Buffer &formatRequest(const std::string &url, http_method_e req); 193 // format a response to the 'echo' test used for testing Gnash. 194 cygnal::Buffer &formatEchoResponse(const std::string &num, cygnal::Element &el); 195 cygnal::Buffer &formatEchoResponse(const std::string &num, cygnal::Buffer &data); 196 cygnal::Buffer &formatEchoResponse(const std::string &num, std::uint8_t *data, size_t size); 197 formatMethod(const std::string & data)198 cygnal::Buffer &formatMethod(const std::string &data) 199 {return formatCommon("Method: " + data); }; 200 cygnal::Buffer &formatDate(); 201 cygnal::Buffer &formatServer(); 202 cygnal::Buffer &formatServer(const std::string &data); formatReferer(const std::string & data)203 cygnal::Buffer &formatReferer(const std::string &data) 204 {return formatCommon("Referer: " + data); }; formatConnection(const std::string & data)205 cygnal::Buffer &formatConnection(const std::string &data) 206 {return formatCommon("Connection: " + data); }; formatKeepAlive(const std::string & data)207 cygnal::Buffer &formatKeepAlive(const std::string &data) 208 {return formatCommon("Keep-Alive: " + data); }; 209 cygnal::Buffer &formatContentLength(); 210 cygnal::Buffer &formatContentLength(std::uint32_t filesize); 211 cygnal::Buffer &formatContentType(); 212 cygnal::Buffer &formatContentType(DiskStream::filetype_e type); formatHost(const std::string & data)213 cygnal::Buffer &formatHost(const std::string &data) 214 {return formatCommon("Host: " + data); }; formatAgent(const std::string & data)215 cygnal::Buffer &formatAgent(const std::string &data) 216 {return formatCommon("User-Agent: " + data); }; formatAcceptRanges(const std::string & data)217 cygnal::Buffer &formatAcceptRanges(const std::string &data) 218 {return formatCommon("Accept-Ranges: " + data); }; 219 cygnal::Buffer &formatLastModified(); formatLastModified(const std::string & data)220 cygnal::Buffer &formatLastModified(const std::string &data) 221 {return formatCommon("Last-Modified: " + data); } formatEtag(const std::string & data)222 cygnal::Buffer &formatEtag(const std::string &data) 223 {return formatCommon("Etag: " + data); }; formatLanguage(const std::string & data)224 cygnal::Buffer &formatLanguage(const std::string &data) 225 {return formatCommon("Accept-Language: " + data); }; formatCharset(const std::string & data)226 cygnal::Buffer &formatCharset(const std::string &data) 227 {return formatCommon("Accept-Charset: " + data); }; formatEncoding(const std::string & data)228 cygnal::Buffer &formatEncoding(const std::string &data) 229 {return formatCommon("Accept-Encoding: " + data); }; formatTE(const std::string & data)230 cygnal::Buffer &formatTE(const std::string &data) 231 {return formatCommon("TE: " + data); }; 232 // All HTTP messages are terminated with a blank line terminateHeader()233 void terminateHeader() { _buffer += "\r\n"; }; 234 235 // cygnal::Buffer &formatErrorResponse(http_status_e err); 236 237 // Return the header that's been built up. getHeader()238 std::uint8_t *getHeader() { return _buffer.reference(); }; 239 240 // Return the header that's been built up. getBuffer()241 cygnal::Buffer &getBuffer() { return _buffer; }; 242 243 // // Return the body that's been built up. 244 // std::string getBody() { return _body.str(); }; 245 246 // Get the file type, so we know how to set the 247 // Content-type in the header. 248 // filetype_e getFileType(std::string &filespec); 249 // amf::AMF::filetype_e getFileStats(std::string &filespec); 250 void dump(); 251 252 /// \brief Receive a message from the other end of the network connection. 253 /// 254 /// @param fd The file descriptor to read from 255 /// 256 /// @return The number of bytes sent 257 int recvMsg(int fd); 258 int recvMsg(int fd, size_t size); 259 260 size_t recvChunked(std::uint8_t *data, size_t size); 261 262 /// \brief Send a message to the other end of the network connection. 263 /// 264 /// @param data A real pointer to the data. 265 /// @param size The number of bytes of data stored. 266 /// @param buf A smart pointer to a Buffer class. 267 /// @param sstr A smart pointer to a Buffer class. 268 /// @param fd The file descriptor to use for writing to the network. 269 /// @param void Send the contents of the _header and _body. 270 /// 271 /// @return The number of bytes sent 272 int sendMsg(); 273 int sendMsg(int fd); 274 int sendMsg(const std::uint8_t *data, size_t size); sendMsg(std::shared_ptr<cygnal::Buffer> & buf)275 int sendMsg(std::shared_ptr<cygnal::Buffer> &buf) 276 { return sendMsg(buf->reference(), buf->size()); }; sendMsg(std::stringstream & sstr)277 int sendMsg(std::stringstream &sstr) 278 { return sendMsg(reinterpret_cast<const std::uint8_t *>(sstr.str().c_str()), sstr.str().size()); }; 279 280 // These accessors are used mostly just for debugging. keepAlive()281 bool keepAlive() { return _keepalive; } keepAlive(bool x)282 void keepAlive(bool x) { _keepalive = x; }; 283 getMaxRequests()284 int getMaxRequests() { return _max_requests; } getFileSize()285 int getFileSize() { return _filesize; } getFilespec()286 std::string &getFilespec() { return _filespec; } getParams()287 std::string &getParams() { return _params; } 288 // std::string &getURL() { return _url; } getStatusCodes()289 std::map<int, struct status_codes *> getStatusCodes() 290 { return _status_codes; } getVersion()291 http_version_t *getVersion() { return &_version; } 292 293 // void setHandler(Handler *hand) { _handler = hand; }; setDocRoot(const std::string & path)294 void setDocRoot(const std::string &path) { _docroot = path; }; getDocRoot()295 std::string &getDocRoot() { return _docroot; }; 296 297 // Pop the first date element off the que popChunk()298 std::shared_ptr<cygnal::Buffer> DSOEXPORT popChunk() { return _que.pop(); }; 299 // Peek at the first date element witjhout removing it from the que peekChunk()300 std::shared_ptr<cygnal::Buffer> DSOEXPORT peekChunk() { return _que.peek(); }; 301 // Get the number of elements in the que sizeChunks()302 size_t DSOEXPORT sizeChunks() { return _que.size(); }; 303 mergeChunks()304 std::shared_ptr<cygnal::Buffer> DSOEXPORT mergeChunks() { return _que.merge(); }; 305 getOperation()306 http_method_e getOperation() { return _cmd; }; 307 308 protected: 309 // Examine the beginning of the data for an HTTP request command 310 // like GET or POST, etc... 311 http_method_e extractCommand(std::uint8_t *data); extractCommand(cygnal::Buffer & data)312 http_method_e extractCommand(cygnal::Buffer &data) 313 { return extractCommand(data.reference()); }; 314 315 typedef boost::char_separator<char> Sep; 316 typedef boost::tokenizer<Sep> Tok; 317 http_method_e _cmd; 318 319 cygnal::Buffer _buffer; 320 CQue _que; 321 322 DiskStream::filetype_e _filetype; 323 std::string _filespec; 324 std::string _params; 325 std::uint32_t _filesize; 326 std::map<int, struct status_codes *> _status_codes; 327 328 std::map<std::string, std::string> _fields; 329 http_version_t _version; 330 331 // Connection parameters we care about 332 bool _keepalive; 333 // Handler *_handler; 334 // These two field hold the data from an RTMPT message 335 int _clientid; 336 int _index; 337 int _max_requests; 338 std::string _docroot; 339 340 bool _close; 341 }; 342 343 // This is the thread for all incoming HTTP connections for the server 344 extern "C" { 345 bool DSOEXPORT http_handler(Network::thread_params_t *args); 346 } 347 348 349 } // end of gnash namespace 350 351 // end of _HTTP_H_ 352 #endif 353 354 355 // local Variables: 356 // mode: C++ 357 // indent-tabs-mode: t 358 // End: 359