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>
17typedef int socklen_t;
18typedef SOCKET NativeSocket;
19#else
20#include <netinet/in.h>
21#include <sys/select.h>
22#include <sys/socket.h>
23#define closesocket close
24typedef 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
37class 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.
54class 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.
145class 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