Home | History | Annotate | Download | only in server
      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:
     39   SocketBase() : socket_(INVALID_SOCKET) { }
     40   explicit SocketBase(NativeSocket socket) : socket_(socket) { }
     41   ~SocketBase() { Close(); }
     42 
     43   NativeSocket socket() const { return socket_; }
     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 
     63   explicit DataSocket(NativeSocket socket)
     64       : SocketBase(socket),
     65         method_(INVALID),
     66         content_length_(0) {
     67   }
     68 
     69   ~DataSocket() {
     70   }
     71 
     72   static const char kCrossOriginAllowHeaders[];
     73 
     74   bool headers_received() const { return method_ != INVALID; }
     75 
     76   RequestMethod method() const { return method_; }
     77 
     78   const std::string& request_path() const { return request_path_; }
     79   std::string request_arguments() const;
     80 
     81   const std::string& data() const { return data_; }
     82 
     83   const std::string& content_type() const { return content_type_; }
     84 
     85   size_t content_length() const { return content_length_; }
     86 
     87   bool request_received() const {
     88     return headers_received() && (method_ != POST || data_received());
     89   }
     90 
     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:
    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