1 /* 2 * libjingle 3 * Copyright 2011, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #ifndef TALK_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_ 29 #define TALK_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_ 30 #pragma once 31 32 #ifdef WIN32 33 #include <winsock2.h> 34 typedef int socklen_t; 35 #else 36 #include <netinet/in.h> 37 #include <sys/select.h> 38 #include <sys/socket.h> 39 #define closesocket close 40 #endif 41 42 #include <string> 43 44 #ifndef SOCKET_ERROR 45 #define SOCKET_ERROR (-1) 46 #endif 47 48 #ifndef INVALID_SOCKET 49 #define INVALID_SOCKET static_cast<int>(~0) 50 #endif 51 52 class SocketBase { 53 public: SocketBase()54 SocketBase() : socket_(INVALID_SOCKET) { } SocketBase(int socket)55 explicit SocketBase(int socket) : socket_(socket) { } ~SocketBase()56 ~SocketBase() { Close(); } 57 socket()58 int socket() const { return socket_; } valid()59 bool valid() const { return socket_ != INVALID_SOCKET; } 60 61 bool Create(); 62 void Close(); 63 64 protected: 65 int socket_; 66 }; 67 68 // Represents an HTTP server socket. 69 class DataSocket : public SocketBase { 70 public: 71 enum RequestMethod { 72 INVALID, 73 GET, 74 POST, 75 OPTIONS, 76 }; 77 DataSocket(int socket)78 explicit DataSocket(int socket) 79 : SocketBase(socket), 80 method_(INVALID), 81 content_length_(0) { 82 } 83 ~DataSocket()84 ~DataSocket() { 85 } 86 87 static const char kCrossOriginAllowHeaders[]; 88 headers_received()89 bool headers_received() const { return method_ != INVALID; } 90 method()91 RequestMethod method() const { return method_; } 92 request_path()93 const std::string& request_path() const { return request_path_; } 94 std::string request_arguments() const; 95 data()96 const std::string& data() const { return data_; } 97 content_type()98 const std::string& content_type() const { return content_type_; } 99 content_length()100 size_t content_length() const { return content_length_; } 101 request_received()102 bool request_received() const { 103 return headers_received() && (method_ != POST || data_received()); 104 } 105 data_received()106 bool data_received() const { 107 return method_ != POST || data_.length() >= content_length_; 108 } 109 110 // Checks if the request path (minus arguments) matches a given path. 111 bool PathEquals(const char* path) const; 112 113 // Called when we have received some data from clients. 114 // Returns false if an error occurred. 115 bool OnDataAvailable(bool* close_socket); 116 117 // Send a raw buffer of bytes. 118 bool Send(const std::string& data) const; 119 120 // Send an HTTP response. The |status| should start with a valid HTTP 121 // response code, followed by a string. E.g. "200 OK". 122 // If |connection_close| is set to true, an extra "Connection: close" HTTP 123 // header will be included. |content_type| is the mime content type, not 124 // including the "Content-Type: " string. 125 // |extra_headers| should be either empty or a list of headers where each 126 // header terminates with "\r\n". 127 // |data| is the body of the message. It's length will be specified via 128 // a "Content-Length" header. 129 bool Send(const std::string& status, bool connection_close, 130 const std::string& content_type, 131 const std::string& extra_headers, const std::string& data) const; 132 133 // Clears all held state and prepares the socket for receiving a new request. 134 void Clear(); 135 136 protected: 137 // A fairly relaxed HTTP header parser. Parses the method, path and 138 // content length (POST only) of a request. 139 // Returns true if a valid request was received and no errors occurred. 140 bool ParseHeaders(); 141 142 // Figures out whether the request is a GET or POST and what path is 143 // being requested. 144 bool ParseMethodAndPath(const char* begin, size_t len); 145 146 // Determines the length of the body and it's mime type. 147 bool ParseContentLengthAndType(const char* headers, size_t length); 148 149 protected: 150 RequestMethod method_; 151 size_t content_length_; 152 std::string content_type_; 153 std::string request_path_; 154 std::string request_headers_; 155 std::string data_; 156 }; 157 158 // The server socket. Accepts connections and generates DataSocket instances 159 // for each new connection. 160 class ListeningSocket : public SocketBase { 161 public: ListeningSocket()162 ListeningSocket() {} 163 164 bool Listen(unsigned short port); 165 DataSocket* Accept() const; 166 }; 167 168 #endif // TALK_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_ 169