+++ /dev/null
-/*
-
- silchttpserver.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 Pekka Riikonen
-
- This program 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; version 2 of the License.
-
- This program 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.
-
-*/
-
-#include "silc.h"
-#include "silchttpserver.h"
-
-/************************** Types and definitions ***************************/
-
-#define SILC_HTTP_SERVER_TIMEOUT 120 /* Connection timeout */
-#define SILC_HTTP_SERVER_CONNS 2 /* Default number of connections */
-#define SILC_HTTP_SERVER_BUFLEN 1024 /* Default data buffer length */
-#define SILC_HTTP_SERVER_HEADER "HTTP/1.1 200 OK\r\nServer: SILCHTTP/1.0\r\n"
-
-/* HTTP server context */
-struct SilcHttpServerStruct {
- SilcNetListener listener; /* Server listener */
- SilcSchedule schedule; /* Scheduler */
- SilcList allconns; /* All connections */
- SilcList conns; /* Connection free list */
- SilcHttpServerCallback callback; /* Requset callback */
- void *context; /* Request callback context */
-};
-
-/* HTTP connection context */
-struct SilcHttpConnectionStruct {
- struct SilcHttpConnectionStruct *next;
- struct SilcHttpConnectionStruct *next2;
- SilcHttpServer httpd; /* Server */
- SilcStream stream; /* Connection stream */
- SilcBuffer inbuf; /* Read data buffer */
- SilcBuffer outbuf; /* Write data buffer */
- SilcInt64 touched; /* Time last connection was touched */
- SilcMime curheaders; /* HTTP request headers */
- SilcMime headers; /* HTTP reply headers */
- unsigned char *hptr; /* Pointer to start of headers */
- char *method; /* Method */
- char *uri; /* URI */
- unsigned int keepalive : 1; /* Keep alive */
-};
-
-/************************ Static utility functions **************************/
-
-/* Close HTTP connection */
-
-static void silc_http_server_close_connection(SilcHttpConnection conn)
-{
- if (conn->headers) {
- silc_mime_free(conn->headers);
- conn->headers = NULL;
- }
- if (conn->curheaders) {
- silc_mime_free(conn->curheaders);
- conn->curheaders = NULL;
- }
- silc_buffer_clear(conn->inbuf);
- silc_buffer_clear(conn->outbuf);
- silc_buffer_reset(conn->inbuf);
- silc_buffer_reset(conn->outbuf);
- conn->hptr = conn->method = conn->uri = NULL;
-
- if (conn->keepalive)
- return;
-
- SILC_LOG_DEBUG(("Closing HTTP connection %p", conn));
-
- silc_schedule_task_del_by_context(conn->httpd->schedule, conn);
- silc_stream_set_notifier(conn->stream, conn->httpd->schedule, NULL, NULL);
- silc_stream_destroy(conn->stream);
- conn->stream = NULL;
-
- /* Add to free list */
- silc_list_add(conn->httpd->conns, conn);
-}
-
-/* Parse HTTP data */
-
-static SilcBool silc_http_server_parse(SilcHttpServer httpd,
- SilcHttpConnection conn)
-{
- SilcUInt32 data_len, cll;
- unsigned char *data, *tmp;
- const char *value, *cl;
- SilcBufferStruct postdata;
- int i;
-
- SILC_LOG_DEBUG(("Parsing HTTP data"));
-
- data = silc_buffer_data(conn->inbuf);
- data_len = silc_buffer_len(conn->inbuf);
-
- /* Check for end of headers */
- for (i = 0; i < data_len ; i++) {
- if (data_len - i >= 4 &&
- data[i ] == '\r' && data[i + 1] == '\n' &&
- data[i + 2] == '\r' && data[i + 3] == '\n')
- break;
- }
- if (i == data_len)
- return TRUE;
-
- SILC_LOG_HEXDUMP(("HTTP data"), silc_buffer_data(conn->inbuf),
- silc_buffer_len(conn->inbuf));
-
- if (!conn->method && !conn->uri) {
- tmp = memchr(data, '\n', data_len);
- if (!tmp || tmp[-1] != '\r') {
- if (data_len < SILC_HTTP_SERVER_BUFLEN)
- return TRUE;
- return FALSE;
- }
- *tmp = 0;
-
- /* Get method */
- if (strchr(data, ' '))
- *strchr(data, ' ') = 0;
- conn->method = data;
- SILC_LOG_DEBUG(("Method: '%s'", conn->method));
-
- /* Get URI */
- tmp = memchr(data, '\0', data_len);
- if (!tmp) {
- if (data_len < SILC_HTTP_SERVER_BUFLEN)
- return TRUE;
- return FALSE;
- }
- tmp++;
- if (strchr(tmp, ' '))
- *strchr(tmp, ' ') = 0;
- conn->uri = tmp;
- SILC_LOG_DEBUG(("URI: '%s'", conn->uri));
-
- /* Protocol version compatibility */
- tmp = ((unsigned char *)memchr(tmp, '\0', data_len - (tmp - data))) + 1;
- SILC_LOG_DEBUG(("Protocol: %s", tmp));
- if (strstr(tmp, "HTTP/1.0"))
- conn->keepalive = FALSE;
- if (strstr(tmp, "HTTP/1.1"))
- conn->keepalive = TRUE;
- if (strstr(tmp, "HTTP/1.2"))
- conn->keepalive = TRUE;
-
- /* Get HTTP headers */
- tmp = memchr(tmp, '\0', data_len - (tmp - data));
- if (!tmp) {
- if (data_len < SILC_HTTP_SERVER_BUFLEN)
- return TRUE;
- return FALSE;
- }
- if (data_len - (tmp - data) < 2) {
- if (data_len < SILC_HTTP_SERVER_BUFLEN)
- return TRUE;
- return FALSE;
- }
- conn->hptr = ++tmp;
- }
-
- /* Parse headers and data area */
- conn->curheaders = silc_mime_decode(NULL, conn->hptr,
- data_len - (conn->hptr - data));
- if (!conn->curheaders)
- return FALSE;
-
- /* Check for persistent connection */
- value = silc_mime_get_field(conn->curheaders, "Connection");
- if (value && !strcasecmp(value, "close"))
- conn->keepalive = FALSE;
-
- /* Deliver request to caller */
- if (!strcasecmp(conn->method, "GET") || !strcasecmp(conn->method, "HEAD")) {
- httpd->callback(httpd, conn, conn->uri, conn->method,
- NULL, httpd->context);
-
- } else if (!strcasecmp(conn->method, "POST")) {
- /* Get POST data */
- tmp = (unsigned char *)silc_mime_get_data(conn->curheaders, &data_len);
- if (!tmp)
- return FALSE;
-
- /* Check we have received all data */
- cl = silc_mime_get_field(conn->curheaders, "Content-Length");
- if (cl && sscanf(cl, "%lu", &cll) == 1) {
- if (data_len < cll) {
- /* More data to come */
- silc_mime_free(conn->curheaders);
- conn->curheaders = NULL;
- return TRUE;
- }
- }
-
- silc_buffer_set(&postdata, tmp, data_len);
- SILC_LOG_HEXDUMP(("HTTP POST data"), tmp, data_len);
-
- httpd->callback(httpd, conn, conn->uri, conn->method,
- &postdata, httpd->context);
- } else {
- /* Send bad request */
- silc_http_server_send_error(httpd, conn, "400 Bad Request",
- "<body><h1>400 Bad Request</h1><body>");
- return TRUE;
- }
-
- return TRUE;
-}
-
-/* Send HTTP data to connection */
-
-static SilcBool silc_http_server_send_internal(SilcHttpServer httpd,
- SilcHttpConnection conn,
- SilcBuffer data,
- SilcBool headers)
-{
- int ret;
-
- SILC_LOG_HEXDUMP(("HTTP data"), silc_buffer_data(data),
- silc_buffer_len(data));
-
- /* Write the packet to the stream */
- while (silc_buffer_len(data) > 0) {
- ret = silc_stream_write(conn->stream, silc_buffer_data(data),
- silc_buffer_len(data));
- if (ret == 0 || ret == - 2)
- return FALSE;
-
- if (ret == -1) {
- /* Cannot write now, write later. */
- if (silc_buffer_len(data) - ret >= silc_buffer_taillen(conn->outbuf))
- if (!silc_buffer_realloc(conn->outbuf,
- silc_buffer_truelen(conn->outbuf) +
- silc_buffer_len(data) - ret)) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return FALSE;
- }
- silc_buffer_pull_tail(conn->outbuf, silc_buffer_len(data) - ret);
- silc_buffer_put(conn->outbuf, silc_buffer_data(data) + ret,
- silc_buffer_len(data) - ret);
- return TRUE;
- }
-
- /* Wrote data */
- silc_buffer_pull(data, ret);
- }
-
- if (!headers) {
- /* Data sent, close connection */
- SILC_LOG_DEBUG(("Data sent %p", conn));
- silc_http_server_close_connection(conn);
- }
-
- return TRUE;
-}
-
-/* Allocate connection context */
-
-static SilcHttpConnection silc_http_server_alloc_connection(void)
-{
- SilcHttpConnection conn;
-
- conn = silc_calloc(1, sizeof(*conn));
- if (!conn)
- return NULL;
-
- conn->inbuf = silc_buffer_alloc(SILC_HTTP_SERVER_BUFLEN);
- if (!conn->inbuf) {
- silc_free(conn);
- return NULL;
- }
-
- conn->outbuf = silc_buffer_alloc(SILC_HTTP_SERVER_BUFLEN);
- if (!conn->outbuf) {
- silc_buffer_free(conn->inbuf);
- silc_free(conn);
- return NULL;
- }
-
- silc_buffer_reset(conn->inbuf);
- silc_buffer_reset(conn->outbuf);
-
- return conn;
-}
-
-/* Check if connection has timedout */
-
-SILC_TASK_CALLBACK(silc_http_server_connection_timeout)
-{
- SilcHttpConnection conn = context;
- SilcInt64 curtime = silc_time();
-
- if (curtime - conn->touched > SILC_HTTP_SERVER_TIMEOUT) {
- SILC_LOG_DEBUG(("Connection timeout %p", conn));
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return;
- }
-
- silc_schedule_task_add_timeout(conn->httpd->schedule,
- silc_http_server_connection_timeout, conn,
- SILC_HTTP_SERVER_TIMEOUT, 0);
-}
-
-/* Data I/O callback */
-
-static void silc_http_server_io(SilcStream stream, SilcStreamStatus status,
- void *context)
-{
- SilcHttpConnection conn = context;
- SilcHttpServer httpd = conn->httpd;
- int ret;
-
- switch (status) {
- case SILC_STREAM_CAN_READ:
- SILC_LOG_DEBUG(("Read HTTP data %p", conn));
-
- conn->touched = silc_time();
-
- /* Make sure we have fair amount of free space in inbuf */
- if (silc_buffer_taillen(conn->inbuf) < SILC_HTTP_SERVER_BUFLEN)
- if (!silc_buffer_realloc(conn->inbuf, silc_buffer_truelen(conn->inbuf) +
- SILC_HTTP_SERVER_BUFLEN * 2)) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return;
- }
-
- /* Read data from stream */
- ret = silc_stream_read(conn->stream, conn->inbuf->tail,
- silc_buffer_taillen(conn->inbuf));
-
- if (ret == 0 || ret == -2) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return;
- }
-
- if (ret == -1) {
- /* Cannot read now, do it later. */
- silc_buffer_pull(conn->inbuf, silc_buffer_len(conn->inbuf));
- return;
- }
-
- SILC_LOG_DEBUG(("Read %d bytes data", ret));
-
- /* Parse the data */
- silc_buffer_pull_tail(conn->inbuf, ret);
- if (!silc_http_server_parse(httpd, conn)) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- }
-
- break;
-
- case SILC_STREAM_CAN_WRITE:
- SILC_LOG_DEBUG(("Write HTTP data %p", conn));
-
- conn->touched = silc_time();
-
- /* Write pending data to stream */
- while (silc_buffer_len(conn->outbuf) > 0) {
- ret = silc_stream_write(conn->stream, silc_buffer_data(conn->outbuf),
- silc_buffer_len(conn->outbuf));
-
- if (ret == 0 || ret == -2) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return;
- }
-
- if (ret == -1)
- /* Cannot write now, write later. */
- return;
-
- /* Wrote data */
- silc_buffer_pull(conn->outbuf, ret);
- }
-
- /* Data sent, close connection */
- SILC_LOG_DEBUG(("Data sent"));
- silc_http_server_close_connection(conn);
- break;
-
- default:
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- break;
- }
-}
-
-/* Accepts new connection */
-
-static void silc_http_server_new_connection(SilcResult status,
- SilcStream stream,
- void *context)
-{
- SilcHttpServer httpd = context;
- SilcHttpConnection conn;
- const char *hostname = NULL, *ip = NULL;
-
- /* Get free connection */
- silc_list_start(httpd->conns);
- conn = silc_list_get(httpd->conns);
- if (!conn) {
- /* Add new connection */
- conn = silc_http_server_alloc_connection();
- if (!conn) {
- silc_stream_destroy(stream);
- return;
- }
- silc_list_add(httpd->allconns, conn);
- }
- silc_list_del(httpd->conns, conn);
-
- conn->httpd = httpd;
- conn->stream = stream;
-
- silc_socket_stream_get_info(stream, NULL, &hostname, &ip, NULL);
- SILC_LOG_INFO(("HTTPD: New connection %s (%s)", hostname, ip));
- SILC_LOG_DEBUG(("New connection %p", conn));
-
- /* Schedule the connection for data I/O */
- silc_stream_set_notifier(stream, httpd->schedule, silc_http_server_io, conn);
-
- /* Add connection timeout check */
- silc_schedule_task_add_timeout(httpd->schedule,
- silc_http_server_connection_timeout, conn,
- SILC_HTTP_SERVER_TIMEOUT, 0);
-}
-
-
-/******************************* Public API *********************************/
-
-/* Allocate HTTP server */
-
-SilcHttpServer silc_http_server_alloc(const char *ip, SilcUInt16 port,
- SilcSchedule schedule,
- SilcHttpServerCallback callback,
- void *context)
-{
- SilcHttpServer httpd;
- SilcHttpConnection conn;
- int i;
-
- SILC_LOG_DEBUG(("Start HTTP server at %s:%d", ip, port));
-
- if (!schedule)
- schedule = silc_schedule_get_global();
-
- if (!ip || !schedule || !callback)
- return FALSE;
-
- httpd = silc_calloc(1, sizeof(*httpd));
- if (!httpd)
- return NULL;
-
- /* Create server listener */
- httpd->listener =
- silc_net_tcp_create_listener(&ip, 1, port, TRUE, FALSE, schedule,
- silc_http_server_new_connection, httpd);
- if (!httpd->listener) {
- SILC_LOG_ERROR(("Could not bind HTTP server at %s:%d", ip, port));
- silc_http_server_free(httpd);
- return NULL;
- }
-
- httpd->schedule = schedule;
- httpd->callback = callback;
- httpd->context = context;
-
- silc_list_init(httpd->conns, struct SilcHttpConnectionStruct, next);
- silc_list_init(httpd->allconns, struct SilcHttpConnectionStruct, next2);
-
- /* Allocate connections list */
- for (i = 0; i < SILC_HTTP_SERVER_CONNS; i++) {
- conn = silc_http_server_alloc_connection();
- if (!conn)
- break;
- silc_list_add(httpd->conns, conn);
- silc_list_add(httpd->allconns, conn);
- conn->httpd = httpd;
- }
-
- SILC_LOG_DEBUG(("HTTP Server started"));
-
- return httpd;
-}
-
-/* Free HTTP server */
-
-void silc_http_server_free(SilcHttpServer httpd)
-{
- SilcHttpConnection conn;
-
- silc_list_start(httpd->allconns);
- while ((conn = silc_list_get(httpd->allconns))) {
- conn->keepalive = FALSE;
- if (conn->httpd && conn->stream)
- silc_http_server_close_connection(conn);
- silc_buffer_free(conn->inbuf);
- silc_buffer_free(conn->outbuf);
- silc_free(conn);
- }
-
- if (httpd->listener)
- silc_net_close_listener(httpd->listener);
-
- silc_free(httpd);
-}
-
-/* Send HTTP data to connection */
-
-SilcBool silc_http_server_send(SilcHttpServer httpd,
- SilcHttpConnection conn,
- SilcBuffer data)
-{
- SilcBufferStruct h;
- unsigned char *headers, tmp[16];
- SilcUInt32 headers_len;
- SilcBool ret;
-
- SILC_LOG_DEBUG(("Sending HTTP data"));
-
- conn->touched = silc_time();
-
- /* Write headers */
- silc_buffer_set(&h, SILC_HTTP_SERVER_HEADER,
- strlen(SILC_HTTP_SERVER_HEADER));
- ret = silc_http_server_send_internal(httpd, conn, &h, TRUE);
- if (!ret) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return FALSE;
- }
-
- if (!conn->headers) {
- conn->headers = silc_mime_alloc();
- if (!conn->headers) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return FALSE;
- }
- }
-
- silc_mime_add_field(conn->headers, "Last-Modified",
- silc_time_string(conn->touched));
- silc_snprintf(tmp, sizeof(tmp), "%d", (int)silc_buffer_len(data));
- silc_mime_add_field(conn->headers, "Content-Length", tmp);
- if (conn->keepalive) {
- silc_mime_add_field(conn->headers, "Connection", "keep-alive");
- silc_snprintf(tmp, sizeof(tmp), "%d", (int)SILC_HTTP_SERVER_TIMEOUT);
- silc_mime_add_field(conn->headers, "Keep-alive", tmp);
- }
-
- headers = silc_mime_encode(conn->headers, &headers_len);
- if (headers) {
- silc_buffer_set(&h, headers, headers_len);
- if (!silc_http_server_send_internal(httpd, conn, &h, TRUE)) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return FALSE;
- }
- silc_free(headers);
- }
-
- /* Write the page data */
- return silc_http_server_send_internal(httpd, conn, data, FALSE);
-}
-
-/* Send error reply */
-
-SilcBool silc_http_server_send_error(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *error,
- const char *error_message)
-{
- SilcBool ret;
- SilcBufferStruct data;
-
- memset(&data, 0, sizeof(data));
- silc_buffer_strformat(&data,
- "HTTP/1.1 ", error, "\r\n\r\n", error_message,
- SILC_STRFMT_END);
-
- /* Send the message */
- ret = silc_http_server_send_internal(httpd, conn, &data, FALSE);
-
- silc_buffer_purge(&data);
-
- /* Close connection */
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
-
- return ret;
-}
-
-/* Get field */
-
-const char *silc_http_server_get_header(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *field)
-{
- if (!conn->curheaders)
- return NULL;
- return silc_mime_get_field(conn->curheaders, field);
-}
-
-/* Add field */
-
-SilcBool silc_http_server_add_header(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *field,
- const char *value)
-{
- SILC_LOG_DEBUG(("Adding header %s:%s", field, value));
-
- if (!conn->headers) {
- conn->headers = silc_mime_alloc();
- if (!conn->headers) {
- silc_http_server_close_connection(conn);
- return FALSE;
- }
- }
-
- silc_mime_add_field(conn->headers, field, value);
- return TRUE;
-}
+++ /dev/null
-/*
-
- silchttpserver.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 Pekka Riikonen
-
- This program 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; version 2 of the License.
-
- This program 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.
-
-*/
-
-/****h* silchttp/SILC HTTP Server Interface
- *
- * DESCRIPTION
- *
- * Very simple HTTP server interface. This HTTP server supports basic HTTP
- * features. All pages on the server are dynamically created by the caller
- * of this interface. The server does not support plugins, modules, cgi-bin,
- * server-side includes or any other special features. Naturally, the caller
- * of this interface may itself implement such features.
- *
- ***/
-
-#ifndef SILCHTTPSERVER_H
-#define SILCHTTPSERVER_H
-
-/****s* silchttp/SilcHTTPServer/SilcHttpServer
- *
- * NAME
- *
- * typedef struct SilcHttpServerStruct *SilcHttpServer;
- *
- * DESCRIPTION
- *
- * The actual HTTP server allocated with silc_http_server_alloc and
- * freed with silc_http_server_free.
- *
- ***/
-typedef struct SilcHttpServerStruct *SilcHttpServer;
-
-/****s* silchttp/SilcHTTPServer/SilcHttpConnection
- *
- * NAME
- *
- * typedef struct SilcHttpConnectionStruct *SilcHttpConnection;
- *
- * DESCRIPTION
- *
- * HTTP connection context. This is allocated by the library and
- * delivered to application in SilcHttpServerCallback callbcak function.
- * It is given as argument to many silc_http_server_* functions.
- * It is freed automatically by the library.
- *
- ***/
-typedef struct SilcHttpConnectionStruct *SilcHttpConnection;
-
-/****f* silchttp/SilcHTTPServer/SilcHttpServerCallback
- *
- * SYNOPSIS
- *
- * typedef void (*SilcHttpServerCallback)(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * const char *uri,
- * const char *method,
- * SilcBuffer data,
- * void *context);
- *
- * DESCRIPTION
- *
- * The HTTP request callback that is called everytime a new HTTP request
- * comes from a HTTP client. The `uri' is the requested URI (web page),
- * and the `method' is the HTTP request method (GET, POST, etc.). The
- * `data' is non-NULL only if the `method' is POST, and it includes the
- * the POST data.
- *
- * The requested web page must be returned to the HTTP client from this
- * callback by calling silc_http_server_send or error is returned by
- * calling silc_http_server_send_error.
- *
- * The silc_http_server_get_header may be called to find a specific
- * HTTP header from this request. New headers may be added to the
- * reply by calling silc_http_server_add_header.
- *
- ***/
-typedef void (*SilcHttpServerCallback)(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *uri,
- const char *method,
- SilcBuffer data,
- void *context);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_alloc
- *
- * SYNOPSIS
- *
- * SilcHttpServer
- * silc_http_server_alloc(const char *ip, SilcUInt16 port,
- * SilcSchedule schedule,
- * SilcHttpServerCallback callback, void *context);
- *
- * DESCRIPTION
- *
- * Allocates HTTP server and binds it to the IP address `ip' on the
- * `port'. The `callback' with `context' will be called everytime a new
- * HTTP request comes to the server from a HTTP client. In that callback
- * the caller must then reply with the requested Web page or with error.
- * If the `schedule' is NULL this will call silc_schedule_get_global to
- * try to get global scheduler.
- *
- ***/
-SilcHttpServer silc_http_server_alloc(const char *ip, SilcUInt16 port,
- SilcSchedule schedule,
- SilcHttpServerCallback callback,
- void *context);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_free
- *
- * SYNOPSIS
- *
- * void silc_http_server_free(SilcHttpServer httpd);
- *
- * DESCRIPTION
- *
- * Close HTTP server and free all resources.
- *
- ***/
-void silc_http_server_free(SilcHttpServer httpd);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_send
- *
- * SYNOPSIS
- *
- * SilcBool silc_http_server_send(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * SilcBuffer data);
- *
- * DESCRIPTION
- *
- * Send the HTTP data indicated by `data' buffer into the connection
- * indicated by `conn'. Returns TRUE after the data is sent, and FALSE
- * if error occurred. Usually the `data' would be the requested web page.
- *
- ***/
-SilcBool silc_http_server_send(SilcHttpServer httpd,
- SilcHttpConnection conn,
- SilcBuffer data);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_send_error
- *
- * SYNOPSIS
- *
- * SilcBool silc_http_server_send_error(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * const char *error,
- * const char *error_message);
- *
- * DESCRIPTION
- *
- * Send HTTP error back to the connection indicated by `conn'. The
- * `error' is one of the 4xx or 5xx errors defined by the HTTP protocol.
- * The `error_message' is the optional error message sent to the
- * connection. Returns FALSE if the error could not be sent.
- *
- * Typical errors are: 400 Bad Request
- * 403 Forbidden
- * 404 Not Found
- *
- * EXAMPLE
- *
- * silc_http_server_send_error(httpd, conn, "400 Bad Request",
- * "<body><h1>400 Bad Request!!</h1></body>");
- *
- ***/
-SilcBool silc_http_server_send_error(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *error,
- const char *error_message);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_get_header
- *
- * SYNOPSIS
- *
- * const char *silc_http_server_get_header(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * const char *field);
- *
- * DESCRIPTION
- *
- * Finds a header field indicated by `field' from the current HTTP
- * request sent by the HTTP client. Returns the field value or NULL
- * if such header field does not exist.
- *
- ***/
-const char *silc_http_server_get_header(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *field);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_add_header
- *
- * SYNOPSIS
- *
- * SilcBool silc_http_server_add_header(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * const char *field,
- * const char *value);
- *
- * DESCRIPTION
- *
- * Adds a new header to the HTTP headers to be sent back to the
- * HTTP client. This may be called to add needed headers to the
- * HTTP reply.
- *
- * EXAMPLE
- *
- * silc_http_server_add_header(httpd, conn, "Content-Type", "image/jpeg");
- * silc_http_server_send(httpd, conn, image_data);
- *
- ***/
-SilcBool silc_http_server_add_header(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *field,
- const char *value);
-
-#endif /* SILCHTTPSERVER_H */
+++ /dev/null
-/* SilcHttpServer tests */
-/* Actually this is almost a full-fledged HTTP server. It can serve HTML
- and PHP pages pretty well. In PHP the variables passed in URI with '?'
- work in PHP script, with this HTTPD of ours, only if $_REQUEST variable
- is used to fetch them (limitation in PHP command line version). In other
- ways '?' in URI is not supported. */
-/* Usage: ./test_silchttpserver [-d] [<htdocsdir>] */
-
-#include "silc.h"
-#include "../silchttpserver.h"
-#include "../silchttpphp.h"
-
-char *htdocs = ".";
-
-/* Add proper content type to reply per URI */
-
-static void http_content_type(SilcHttpServer httpd, SilcHttpConnection conn,
- const char *uri)
-{
- const char *type;
-
- type = silc_http_server_get_header(httpd, conn, "Content-Type");
- if (type)
- silc_http_server_add_header(httpd, conn, "Content-Type", type);
- else if (strstr(uri, ".jpg"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "image/jpeg");
- else if (strstr(uri, ".gif"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "image/gif");
- else if (strstr(uri, ".png"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "image/png");
- else if (strstr(uri, ".css"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "text/css");
- else if (strstr(uri, ".htm"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "text/html");
- else if (strstr(uri, ".php"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "text/html");
-}
-
-/* Serve pages */
-
-static void http_callback_file(SilcHttpServer httpd, SilcHttpConnection conn,
- const char *uri, const char *method,
- SilcBuffer data, void *context)
-{
- SilcBufferStruct page;
- SilcBuffer php;
- char *filedata, filename[256];
- SilcUInt32 data_len;
- SilcBool usephp = FALSE;
-
- if (!strcasecmp(method, "GET")) {
- if (strstr(uri, ".php"))
- usephp = TRUE;
-
- if (!strcmp(uri, "/"))
- snprintf(filename, sizeof(filename), "%s/index.html", htdocs);
- else
- snprintf(filename, sizeof(filename), "%s%s", htdocs, uri);
-
- if (strchr(filename, '?'))
- *strchr(filename, '?') = ' ';
- while (strchr(filename, '&'))
- *strchr(filename, '&') = ' ';
-
- SILC_LOG_DEBUG(("Filename: '%s'", filename));
-
- if (!usephp) {
- filedata = silc_file_readfile(filename, &data_len, NULL);
- if (!filedata) {
- silc_http_server_send_error(httpd, conn, "404 Not Found",
- "<body><h1>404 Not Found</h1><p>The page you are looking for cannot be located</body>");
- return;
- }
-
- http_content_type(httpd, conn, uri);
-
- /* Send page */
- silc_buffer_set(&page, filedata, data_len);
- silc_http_server_send(httpd, conn, &page);
- silc_buffer_purge(&page);
- } else {
- php = silc_http_php_file(filename);
- if (!php) {
- silc_http_server_send_error(httpd, conn, "404 Not Found",
- "<body><h1>404 Not Found</h1><p>The page you are looking for cannot be located</body>");
- return;
- }
-
- http_content_type(httpd, conn, uri);
-
- /* Send page */
- silc_http_server_send(httpd, conn, php);
- silc_buffer_free(php);
- }
-
- return;
- }
-
- silc_http_server_send_error(httpd, conn, "404 Not Found",
- "<body><h1>404 Not Found</h1><p>The page you are looking for cannot be located</body>");
-}
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcSchedule schedule;
- SilcHttpServer httpd;
-
- if (argc > 1) {
- if (!strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*http*,*mime*");
- if (argc > 2)
- htdocs = argv[2];
- } else {
- htdocs = argv[1];
- }
- }
-
- signal(SIGPIPE, SIG_IGN);
-
- SILC_LOG_DEBUG(("Allocating scheduler"));
- schedule = silc_schedule_init(0, NULL, NULL);
- if (!schedule)
- goto err;
-
- SILC_LOG_DEBUG(("Allocating HTTP server at 127.0.0.1:5000"));
- httpd = silc_http_server_alloc("127.0.0.1", 5000, schedule,
- http_callback_file, NULL);
- if (!httpd)
- goto err;
-
- silc_schedule(schedule);
-
- silc_schedule_uninit(schedule);
-
- success = TRUE;
-
- err:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}