1 /*
2  *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef WEBRTC_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
12 #define WEBRTC_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
13 #pragma once
14 
15 #ifdef WIN32
16 #include <winsock2.h>
17 typedef int socklen_t;
18 typedef SOCKET NativeSocket;
19 #else
20 #include <netinet/in.h>
21 #include <sys/select.h>
22 #include <sys/socket.h>
23 #define closesocket close
24 typedef int NativeSocket;
25 
26 #ifndef SOCKET_ERROR
27 #define SOCKET_ERROR (-1)
28 #endif
29 
30 #ifndef INVALID_SOCKET
31 #define INVALID_SOCKET  static_cast<NativeSocket>(-1)
32 #endif
33 #endif
34 
35 #include <string>
36 
37 class SocketBase {
38  public:
SocketBase()39   SocketBase() : socket_(INVALID_SOCKET) { }
SocketBase(NativeSocket socket)40   explicit SocketBase(NativeSocket socket) : socket_(socket) { }
~SocketBase()41   ~SocketBase() { Close(); }
42 
socket()43   NativeSocket socket() const { return socket_; }
valid()44   bool valid() const { return socket_ != INVALID_SOCKET; }
45 
46   bool Create();
47   void Close();
48 
49  protected:
50   NativeSocket socket_;
51 };
52 
53 // Represents an HTTP server socket.
54 class DataSocket : public SocketBase {
55  public:
56   enum RequestMethod {
57     INVALID,
58     GET,
59     POST,
60     OPTIONS,
61   };
62 
DataSocket(NativeSocket socket)63   explicit DataSocket(NativeSocket socket)
64       : SocketBase(socket),
65         method_(INVALID),
66         content_length_(0) {
67   }
68 
~DataSocket()69   ~DataSocket() {
70   }
71 
72   static const char kCrossOriginAllowHeaders[];
73 
headers_received()74   bool headers_received() const { return method_ != INVALID; }
75 
method()76   RequestMethod method() const { return method_; }
77 
request_path()78   const std::string& request_path() const { return request_path_; }
79   std::string request_arguments() const;
80 
data()81   const std::string& data() const { return data_; }
82 
content_type()83   const std::string& content_type() const { return content_type_; }
84 
content_length()85   size_t content_length() const { return content_length_; }
86 
request_received()87   bool request_received() const {
88     return headers_received() && (method_ != POST || data_received());
89   }
90 
data_received()91   bool data_received() const {
92     return method_ != POST || data_.length() >= content_length_;
93   }
94 
95   // Checks if the request path (minus arguments) matches a given path.
96   bool PathEquals(const char* path) const;
97 
98   // Called when we have received some data from clients.
99   // Returns false if an error occurred.
100   bool OnDataAvailable(bool* close_socket);
101 
102   // Send a raw buffer of bytes.
103   bool Send(const std::string& data) const;
104 
105   // Send an HTTP response.  The |status| should start with a valid HTTP
106   // response code, followed by a string.  E.g. "200 OK".
107   // If |connection_close| is set to true, an extra "Connection: close" HTTP
108   // header will be included.  |content_type| is the mime content type, not
109   // including the "Content-Type: " string.
110   // |extra_headers| should be either empty or a list of headers where each
111   // header terminates with "\r\n".
112   // |data| is the body of the message.  It's length will be specified via
113   // a "Content-Length" header.
114   bool Send(const std::string& status, bool connection_close,
115             const std::string& content_type,
116             const std::string& extra_headers, const std::string& data) const;
117 
118   // Clears all held state and prepares the socket for receiving a new request.
119   void Clear();
120 
121  protected:
122   // A fairly relaxed HTTP header parser.  Parses the method, path and
123   // content length (POST only) of a request.
124   // Returns true if a valid request was received and no errors occurred.
125   bool ParseHeaders();
126 
127   // Figures out whether the request is a GET or POST and what path is
128   // being requested.
129   bool ParseMethodAndPath(const char* begin, size_t len);
130 
131   // Determines the length of the body and it's mime type.
132   bool ParseContentLengthAndType(const char* headers, size_t length);
133 
134  protected:
135   RequestMethod method_;
136   size_t content_length_;
137   std::string content_type_;
138   std::string request_path_;
139   std::string request_headers_;
140   std::string data_;
141 };
142 
143 // The server socket.  Accepts connections and generates DataSocket instances
144 // for each new connection.
145 class ListeningSocket : public SocketBase {
146  public:
ListeningSocket()147   ListeningSocket() {}
148 
149   bool Listen(unsigned short port);
150   DataSocket* Accept() const;
151 };
152 
153 #endif  // WEBRTC_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
154