15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/*
25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle
35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2011, Google Inc.
45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without
65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met:
75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer.
105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer in the documentation
125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     and/or other materials provided with the distribution.
135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  3. The name of the author may not be used to endorse or promote products
145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     derived from this software without specific prior written permission.
155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */
275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifndef TALK_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#define TALK_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#pragma once
315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <winsock2.h>
345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgtypedef int socklen_t;
355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#else
365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <netinet/in.h>
375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <sys/select.h>
385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <sys/socket.h>
395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#define closesocket close
405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <string>
435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifndef SOCKET_ERROR
455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#define SOCKET_ERROR (-1)
465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifndef INVALID_SOCKET
495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#define INVALID_SOCKET  static_cast<int>(~0)
505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass SocketBase {
535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketBase() : socket_(INVALID_SOCKET) { }
555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  explicit SocketBase(int socket) : socket_(socket) { }
565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ~SocketBase() { Close(); }
575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int socket() const { return socket_; }
595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool valid() const { return socket_ != INVALID_SOCKET; }
605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Create();
625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void Close();
635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org protected:
655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int socket_;
665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Represents an HTTP server socket.
695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass DataSocket : public SocketBase {
705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  enum RequestMethod {
725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    INVALID,
735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    GET,
745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    POST,
755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    OPTIONS,
765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  };
775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  explicit DataSocket(int socket)
795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      : SocketBase(socket),
805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        method_(INVALID),
815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        content_length_(0) {
825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ~DataSocket() {
855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  static const char kCrossOriginAllowHeaders[];
885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool headers_received() const { return method_ != INVALID; }
905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  RequestMethod method() const { return method_; }
925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const std::string& request_path() const { return request_path_; }
945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string request_arguments() const;
955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const std::string& data() const { return data_; }
975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const std::string& content_type() const { return content_type_; }
995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  size_t content_length() const { return content_length_; }
1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool request_received() const {
1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return headers_received() && (method_ != POST || data_received());
1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool data_received() const {
1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return method_ != POST || data_.length() >= content_length_;
1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Checks if the request path (minus arguments) matches a given path.
1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool PathEquals(const char* path) const;
1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Called when we have received some data from clients.
1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Returns false if an error occurred.
1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool OnDataAvailable(bool* close_socket);
1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Send a raw buffer of bytes.
1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Send(const std::string& data) const;
1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Send an HTTP response.  The |status| should start with a valid HTTP
1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // response code, followed by a string.  E.g. "200 OK".
1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // If |connection_close| is set to true, an extra "Connection: close" HTTP
1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // header will be included.  |content_type| is the mime content type, not
1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // including the "Content-Type: " string.
1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // |extra_headers| should be either empty or a list of headers where each
1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // header terminates with "\r\n".
1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // |data| is the body of the message.  It's length will be specified via
1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // a "Content-Length" header.
1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Send(const std::string& status, bool connection_close,
1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            const std::string& content_type,
1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            const std::string& extra_headers, const std::string& data) const;
1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Clears all held state and prepares the socket for receiving a new request.
1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void Clear();
1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org protected:
1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // A fairly relaxed HTTP header parser.  Parses the method, path and
1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // content length (POST only) of a request.
1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Returns true if a valid request was received and no errors occurred.
1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool ParseHeaders();
1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Figures out whether the request is a GET or POST and what path is
1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // being requested.
1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool ParseMethodAndPath(const char* begin, size_t len);
1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Determines the length of the body and it's mime type.
1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool ParseContentLengthAndType(const char* headers, size_t length);
1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org protected:
1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  RequestMethod method_;
1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  size_t content_length_;
1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string content_type_;
1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string request_path_;
1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string request_headers_;
1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string data_;
1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// The server socket.  Accepts connections and generates DataSocket instances
1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// for each new connection.
1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass ListeningSocket : public SocketBase {
1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ListeningSocket() {}
1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Listen(unsigned short port);
1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  DataSocket* Accept() const;
1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // TALK_EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
169