/*
 * Copyright 2012 Steven Gribble
 *
 *  This file is part of the UW CSE 333 lecture code (333lec).
 *
 *  333lec is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  333lec is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with 333proj.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _HTTPSERVER_H_
#define _HTTPSERVER_H_

#include <string>

typedef void (*HandleFn)(int client_fd,
                         std::string requested_URL,
                         std::string client_IP,
                         unsigned short client_port);

class HttpServer {
 public:
  // Attempts to create a listening socket on port "port". If
  // there is an error creating the listening socket, throws a
  // std::runtime_error exception.
  HttpServer(std::string portnum);
  ~HttpServer() { close(listen_fd_); listen_fd_ = 0; }

  // Enter the accept/dispatch loop.  For each successful client HTTP
  // request, invokes "handle".
  void AcceptDispatch(HandleFn handle);

 private:
  // Create a listening socket on port "portnum".  Throws a
  // std::runtime_error on error.  Sets the this->listen_fd_ file
  // descriptor on success, as well as this->server_addr_ and
  // this->server_port_.
  void Listen(std::string portnum);

  // Look up the IP address information associated with the socket.
  // If "peer" is true, looks up on the peer connected to the
  // socket, else looks up on this side of the socket.  Throws
  // a std::runtime_error on failure.
  void GetIPInfo(int fd, bool peer, std::string *addr, std::string *dns) const;

  // Read the HTTP request from client_fd, parse out the request URL,
  // and return it.  Throws a std::runtime_error on failure.
  std::string ParseURL(int client_fd);

  // The listening socket for the server.
  int listen_fd_;

  // The IP address, DNS name, and port the server is listening on,
  // in string form.
  std::string server_addr_;
  std::string server_dns_;
  std::string server_port_;
};

#endif  // _HTTPSERVER_H_