/*
    GSK - a library to write servers
    Copyright (C) 1999-2000 Dave Benson

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

    Contact:
        daveb@ffem.org <Dave Benson>
*/


/*
 * An single connection of an HTTP server.
 */

#ifndef __GSK_HTTP_SERVER_H_
#define __GSK_HTTP_SERVER_H_

typedef struct _GskHttpServerClass GskHttpServerClass;
typedef struct _GskHttpServer GskHttpServer;
typedef struct _GskHttpServlet GskHttpServlet;
typedef struct _GskHttpPredicate GskHttpPredicate;
typedef struct _GskHttpServletList GskHttpServletList;


#include "../gskactorbuffered.h"
#include "gskhttpheader.h"

GtkType gsk_http_server_get_type();
#define GSK_TYPE_HTTP_SERVER			(gsk_http_server_get_type ())
#define GSK_HTTP_SERVER(obj)              (GTK_CHECK_CAST ((obj), GSK_TYPE_HTTP_SERVER, GskHttpServer))
#define GSK_HTTP_SERVER_CLASS(klass)      (GTK_CHECK_CLASS_CAST ((klass), GSK_TYPE_HTTP_SERVER, GskHttpServerClass))
#define GSK_HTTP_SERVER_GET_CLASS(obj)    (GSK_HTTP_SERVER_CLASS(GTK_OBJECT(obj)->klass))
#define GSK_IS_HTTP_SERVER(obj)           (GTK_CHECK_TYPE ((obj), GSK_TYPE_HTTP_SERVER))
#define GSK_IS_HTTP_SERVER_CLASS(klass)   (GTK_CHECK_CLASS_TYPE ((klass), GSK_TYPE_HTTP_SERVER))

struct _GskHttpServerClass
{
  GskActorBufferedClass base_class;
  /*
   * Takes request -- should eventually call
   * gsk_http_server_write_response().
   */
  gboolean              (*process_request)      (GskHttpServer *server,
                                                 GskHttpHeader *header);

  /*
   * Receive POSTed data.
   * (Also applies to PUT.)
   */
  gboolean              (*process_client_post)  (GskHttpServer *server,
                                                 const char    *posted,
                                                 int            postlen);
  
  /*
   * Spew out page contents.
   *
   * Returning  0 means `done with content'.
   * Returning -1 means error.
   * Returning  1 means "content was produced" or just "success".
   *
   * This won't be called unless
   *          ((GskActorBuffered*)server)->ready_to_produce
   * is 1.
   */
  int                   (*produce_page_content) (GskHttpServer *server);

  /* --- language-binding signals --- */
  void                  (*add_servlet)          (GskHttpServer    *server,
						 GskHttpPredicate *predicate,
						 GskHttpServlet   *servlet);
};

/*
 * Description of an HTTP transaction.
 *
 * 1.  Client connects to server.
 * 2.  Server accepts:  client in READING_REQUEST state.
 * 3.  Client writes HTTP request.
 * 4.  Server finishes reading HTTP request;
 *          for HEAD and GET, enter WRITING_RESPONSE state.
 *          for POST and PUT, enter READING_POST state.
 * 5.  Optional:  client posts / server reads post. [enter WRITING_RESPONSE]
 * 7.  Server writes the content of the page.
 * 8.  If the encoding permits, do keepalive and go to step 1,
 *     Otherwise close the connection.
 */
#define GSK_HTTP_SERVER_READING_REQUEST		1
#define GSK_HTTP_SERVER_READING_POST		2
#define GSK_HTTP_SERVER_WRITING_RESPONSE	3
#define GSK_HTTP_SERVER_WRITING_CONTENT		4

struct _GskHttpServer
{
  GskActorBuffered      base;

  unsigned              state;
  GskBuffer             incoming_buffer;
  GskHttpHeader        *request;
  GskHttpHeader        *response;

  /* outputting data with transfer-encoding: chunked. */
  gboolean              chunked;
  int                   chunking_freeze_count;
  GskBuffer             chunk_buffer;   /* for when frozen. */

  /* Number of bytes max to write, or -1 */
  int                   content_remaining;

  /* If processing a POST or PUT request. */
  int                   amount_to_post;

  /* List of available servlets, and the active servlet. */
  GskHttpServletList   *servlets;
  GskHttpServlet       *servlet;
};

/*
 * All these functions are to be used by derivers of GskHttpServer only.
 */
void    gsk_http_server_write_response(GskHttpServer   *server,
                                       GskHttpHeader   *response);
void    gsk_http_server_write_content (GskHttpServer   *server,
                                       const char      *content_piece,
                                       int              content_len);
void    gsk_http_server_write_content_foreign
                                      (GskHttpServer   *server,
                                       const char      *content_piece,
                                       int              content_len,
				       GDestroyNotify   destroy,
				       gpointer         destroy_data);
void    gsk_http_server_fail          (GskHttpServer   *server,
                                       int              status_code);

void    gsk_http_server_freeze        (GskHttpServer   *server);
void    gsk_http_server_thaw          (GskHttpServer   *server);

#endif
