/****************************************************************************
 * netutils/thttpd/libhttpd.h
 * HTTP Protocol Library Definitions
 *
 *   Copyright (C) 2009 Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <gnutt@nuttx.org>
 *
 * Derived from the file of the same name in the original THTTPD package:
 *
 *   Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
 *   All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 ****************************************************************************/

#ifndef __NETUTILS_THTTPD_LIBHTTPD_H
#define __NETUTILS_THTTPD_LIBHTTPD_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <stdint.h>
#include <stdbool.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <time.h>

#include "config.h"
#ifdef CONFIG_THTTPD

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* A few convenient defines. */

#ifndef MAX
#  define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#  define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif

/* Enable special instrumentation to track down "400 Bad Request" problems */

#undef CONFIG_THTTPD_BADREQUEST /* Define to enable "Bad Request" instrumentation */

#ifdef CONFIG_THTTPD_BADREQUEST
#  if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET)
#    undef CONFIG_THTTPD_BADREQUEST
#  else
#    define BADREQUEST(s) nvdbg("Bad Request: \"%s\"\n", s)
#  endif
#endif

#ifndef CONFIG_THTTPD_BADREQUEST
#  undef  BADREQUEST
#  define BADREQUEST(s)
#endif

/* Enable special instrumentation to track down "501 Not Implemented" problems */

#undef CONFIG_THTTPD_NOTIMPLEMENTED /* Define to enable "Not Implemented" instrumentation */

#ifdef CONFIG_THTTPD_NOTIMPLEMENTED
#  if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET)
#    undef CONFIG_THTTPD_NOTIMPLEMENTED
#  else
#    define NOTIMPLEMENTED(s) nvdbg("Not Implemented: \"%s\"\n", s)
#  endif
#endif

#ifndef CONFIG_THTTPD_NOTIMPLEMENTED
#  undef  NOTIMPLEMENTED
#  define NOTIMPLEMENTED(s)
#endif

/* Enable special instrumentation to track down "500 Internal Error" problems */

#undef CONFIG_THTTPD_INTERNALERROR /* Define to enable "Internal Error" instrumentation */

#ifdef CONFIG_THTTPD_INTERNALERROR
#  if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET)
#    undef CONFIG_THTTPD_INTERNALERROR
#  else
#    define INTERNALERROR(s) nvdbg("Internal Error: \"%s\"\n", s)
#  endif
#endif

#ifndef CONFIG_THTTPD_INTERNALERROR
#  undef  INTERNALERROR
#  define INTERNALERROR(s)
#endif

/* Methods */

#define METHOD_UNKNOWN 0
#define METHOD_GET 1
#define METHOD_HEAD 2
#define METHOD_POST 3

/* States for checked_state. */

#define CHST_FIRSTWORD  0
#define CHST_FIRSTWS    1
#define CHST_SECONDWORD 2
#define CHST_SECONDWS   3
#define CHST_THIRDWORD  4
#define CHST_THIRDWS    5
#define CHST_LINE       6
#define CHST_LF         7
#define CHST_CR         8
#define CHST_CRLF       9
#define CHST_CRLFCR     10
#define CHST_BOGUS      11

#define GC_FAIL 0
#define GC_OK 1
#define GC_NO_MORE 2

#define GR_NO_REQUEST 0
#define GR_GOT_REQUEST 1
#define GR_BAD_REQUEST 2

/****************************************************************************
 * Public Type Definitions
 ****************************************************************************/

/* A multi-family sockaddr. */

#ifdef  CONFIG_NET_IPv6
typedef struct sockaddr_in6 httpd_sockaddr;
#else
typedef struct sockaddr_in httpd_sockaddr;
#endif

/* A server. */

typedef struct
{
  char *hostname;
  int   cgi_count;
  int   listen_fd;
} httpd_server;

/* A connection. */

typedef struct
{
  int initialized;
  httpd_server *hs;
  httpd_sockaddr client_addr;
  char *read_buf;
  size_t read_size, read_idx, checked_idx;
  int checked_state;
  int method;
  off_t bytes_to_send;
  off_t bytes_sent;
  char *encodedurl;
  char *decodedurl;
  char *protocol;
  char *origfilename;
  char *expnfilename;
  char *encodings;
  char *pathinfo;
  char *query;
  char *referer;
  char *useragent;
  char *accept;
  char *accepte;
  char *acceptl;
  char *cookie;
  char *contenttype;
  char *reqhost;
  char *hdrhost;
  char *hostdir;
  char *authorization;
  char *remoteuser;
  size_t maxdecodedurl, maxorigfilename, maxexpnfilename, maxencodings,
    maxpathinfo, maxquery, maxaccept, maxaccepte, maxreqhost, maxhostdir,
    maxremoteuser, maxresponse;
#ifdef CONFIG_THTTPD_TILDE_MAP2
  char *altdir;
  size_t maxaltdir;
#endif
  time_t if_modified_since, range_if;
  size_t contentlength;
  char *type;                  /* not malloc()ed */
#ifdef CONFIG_THTTPD_VHOST
  char *vhostname;             /* not malloc()ed */
#endif
  bool mime_flag;
  bool one_one;                /* HTTP/1.1 or better */
  bool got_range;
  bool tildemapped;            /* this connection got tilde-mapped */
  bool keep_alive;
  bool should_linger;
  int conn_fd;                 /* Connection to the client */
  int file_fd;                 /* Descriptor for open, outgoing file */
  off_t range_start;           /* File range start from Range= */
  off_t range_end;             /* File range end from Range= */
  struct stat sb;

  /* This is the I/O buffer that is used to buffer portions of outgoing files */

  uint16_t buflen;             /* Index to first valid data in buffer */
  uint8_t buffer[CONFIG_THTTPD_IOBUFFERSIZE];
} httpd_conn;

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

/* Initializes.  Does the socket(), bind(), and listen().   Returns an
 * httpd_server* which includes a socket fd that you can select() on.
 * Return (httpd_server*) 0 on error.
 */

extern FAR httpd_server *httpd_initialize(FAR httpd_sockaddr *sa);

/* Call to unlisten/close socket(s) listening for new connections. */

extern void httpd_unlisten(httpd_server *hs);

/* Call to shut down. */

extern void httpd_terminate(httpd_server *hs);

/* When a listen fd is ready to read, call this.  It does the accept() and
 * returns an httpd_conn* which includes the fd to read the request from and
 * write the response to.  Returns an indication of whether the accept()
 * failed, succeeded, or if there were no more connections to accept.
 *
 * In order to minimize malloc()s, the caller passes in the httpd_conn.
 * The caller is also responsible for setting initialized to zero before the
 * first call using each different httpd_conn.
 */

extern int httpd_get_conn(httpd_server *hs, int listen_fd, httpd_conn *hc);

/* Checks whether the data in hc->read_buf constitutes a complete request
 * yet.  The caller reads data into hc->read_buf[hc->read_idx] and advances
 * hc->read_idx.  This routine checks what has been read so far, using
 * hc->checked_idx and hc->checked_state to keep track, and returns an
 * indication of whether there is no complete request yet, there is a
 * complete request, or there won't be a valid request due to a syntax error.
 */

extern int httpd_got_request(httpd_conn *hc);

/* Parses the request in hc->read_buf.  Fills in lots of fields in hc,
 * like the URL and the various headers.
 *
 * Returns -1 on error.
 */

extern int httpd_parse_request(httpd_conn *hc);

/* Starts sending data back to the client.  In some cases (directories,
 * CGI programs), finishes sending by itself - in those cases, hc->file_fd
 * is negative.  If there is more data to be sent, then hc->file_fd is a file
 * stream for the file to send.  If you don't have a current timeval
 * handy just pass in 0.
 *
 * Returns -1 on error.
 */

extern int httpd_start_request(httpd_conn *hc, struct timeval *nowP);

/* Actually sends any buffered response text. */

extern void httpd_write_response(httpd_conn *hc);

/* Call this to close down a connection and free the data. */

extern void httpd_close_conn(httpd_conn *hc);

/* Call this to de-initialize a connection struct and *really* free the
 * mallocced strings.
 */

extern void httpd_destroy_conn(httpd_conn *hc);

/* Send an error message back to the client. */

extern void httpd_send_err(httpd_conn *hc, int status, const char *title,
                           const char *extraheads, const char *form, const char *arg);

/* Generate a string representation of a method number. */

extern const char *httpd_method_str(int method);

/* Format a network socket to a string representation. */

extern char *httpd_ntoa(httpd_sockaddr * saP);

/* Set NDELAY mode on a socket. */

extern void httpd_set_ndelay(int fd);

/* Clear NDELAY mode on a socket. */

extern void httpd_clear_ndelay(int fd);

/* Read to requested buffer, accounting for interruptions and EOF */

extern int httpd_read(int fd, const void *buf, size_t nbytes);

/* Write the buffer completely, accounting for interruptions */

extern int httpd_write(int fd, const void *buf, size_t nbytes);

#endif /* CONFIG_THTTPD */
#endif /* __NETUTILS_THTTPD_LIBHTTPD_H */

