Просмотр исходного кода

added :
* configure.ac support for --with-gnutls=PFX
* TLS connection handler in daemon.c
* simple TLS echo client server example

lv-426 17 лет назад
Родитель
Сommit
c51d65ffce
6 измененных файлов с 1449 добавлено и 1007 удалено
  1. 31 0
      configure.ac
  2. 533 501
      src/daemon/daemon.c
  3. 521 503
      src/daemon/internal.h
  4. 29 3
      src/examples/Makefile.am
  5. 153 0
      src/examples/https_echo_client_example.c
  6. 182 0
      src/examples/https_server_example.c

+ 31 - 0
configure.ac

@@ -141,6 +141,37 @@ AC_CHECK_PROG([HAVE_SOCAT],[socat], 1, 0)
 AM_CONDITIONAL(HAVE_ZZUF, test 0 != $HAVE_ZZUF)
 AM_CONDITIONAL(HAVE_SOCAT, test 0 != $HAVE_SOCAT)
 
+# GNUtls linkage
+AC_ARG_WITH(gnutls,
+  [  --with-gnutls=PFX   Base of GNU TLS installation],
+  [AC_MSG_RESULT("$with_gnutls")
+   case $with_gnutls in
+   no)
+     ;;
+   yes)
+	AC_CHECK_HEADERS(gnutls.h,gnutls=true)
+     ;;
+   *)
+    LDFLAGS="-L$with_gnutls/lib $LDFLAGS"
+    CPPFLAGS="-I$with_gnutls/include $CPPFLAGS"
+    AC_CHECK_HEADERS(gnutls/gnutls.h,
+     # check for 'gnutls_global_init' in gnutls.so
+     AC_CHECK_LIB(gnutls,gnutls_global_init,
+       GNUTLS_LIB_PATH="$with_gnutls/lib"
+       GNUTLS_LDFLAGS="-L$with_gnutls/lib"
+       GNUTLS_CPPFLAGS="-I$with_gnutls/include"
+       gnutls=true))
+    LDFLAGS=$SAVE_LDFLAGS
+    CPPFLAGS=$SAVE_CPPFLAGS
+    ;;
+   esac
+  ],
+  [AC_MSG_RESULT([--with-gnutls not specified])])
+  
+AC_SUBST(GNUTLS_LIB_PATH)
+AC_SUBST(GNUTLS_LDFLAGS)
+AC_SUBST(GNUTLS_CPPFLAGS)
+
 AC_SUBST(CPPFLAGS)
 AC_SUBST(LIBS)
 AC_SUBST(LDFLAGS)

Разница между файлами не показана из-за своего большого размера
+ 533 - 501
src/daemon/daemon.c


+ 521 - 503
src/daemon/internal.h

@@ -1,21 +1,21 @@
 /*
-     This file is part of libmicrohttpd
-     (C) 2007 Daniel Pittman and Christian Grothoff
-
-     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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-*/
+ This file is part of libmicrohttpd
+ (C) 2007 Daniel Pittman and Christian Grothoff
+
+ 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
 /**
  * @file internal.h
@@ -27,7 +27,6 @@
 #ifndef INTERNAL_H
 #define INTERNAL_H
 
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -64,101 +63,101 @@
  * fprintf-like helper function for logging debug
  * messages.
  */
-void MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...);
+void MHD_DLOG(const struct MHD_Daemon *daemon, const char *format, ...);
 #endif
 
 /**
  * Process escape sequences ('+'=space, %HH).
  * Updates val in place.
  */
-void MHD_http_unescape (char *val);
+void MHD_http_unescape(char *val);
 
 /**
  * Header or cookie in HTTP request or response.
  */
 struct MHD_HTTP_Header
-{
-  struct MHD_HTTP_Header *next;
+  {
+    struct MHD_HTTP_Header *next;
 
-  char *header;
+    char *header;
 
-  char *value;
+    char *value;
 
-  enum MHD_ValueKind kind;
+    enum MHD_ValueKind kind;
 
-};
+  };
 
 /**
  * Representation of a response.
  */
 struct MHD_Response
-{
-
-  /**
-   * Headers to send for the response.  Initially
-   * the linked list is created in inverse order;
-   * the order should be inverted before sending!
-   */
-  struct MHD_HTTP_Header *first_header;
-
-  /**
-   * Buffer pointing to data that we are supposed
-   * to send as a response.
-   */
-  char *data;
-
-  /**
-   * Closure to give to the content reader
-   * free callback.
-   */
-  void *crc_cls;
-
-  /**
-   * How do we get more data?  NULL if we are
-   * given all of the data up front.
-   */
-  MHD_ContentReaderCallback crc;
-
-  /**
-   * NULL if data must not be freed, otherwise
-   * either user-specified callback or "&free".
-   */
-  MHD_ContentReaderFreeCallback crfc;
-
-  /**
-   * Mutex to synchronize access to data/size and
-   * reference counts.
-   */
-  pthread_mutex_t mutex;
-
-  /**
-   * Reference count for this response.  Free
-   * once the counter hits zero.
-   */
-  unsigned int reference_count;
-
-  /**
-   * Set to -1 if size is not known.
-   */
-  size_t total_size;
-
-  /**
-   * Size of data.
-   */
-  size_t data_size;
-
-  /**
-   * Size of the data buffer.
-   */
-  size_t data_buffer_size;
-
-  /**
-   * At what offset in the stream is the
-   * beginning of data located?
-   */
-  size_t data_start;
-
-};
+  {
+
+    /**
+     * Headers to send for the response.  Initially
+     * the linked list is created in inverse order;
+     * the order should be inverted before sending!
+     */
+    struct MHD_HTTP_Header *first_header;
+
+    /**
+     * Buffer pointing to data that we are supposed
+     * to send as a response.
+     */
+    char *data;
+
+    /**
+     * Closure to give to the content reader
+     * free callback.
+     */
+    void *crc_cls;
+
+    /**
+     * How do we get more data?  NULL if we are
+     * given all of the data up front.
+     */
+    MHD_ContentReaderCallback crc;
+
+    /**
+     * NULL if data must not be freed, otherwise
+     * either user-specified callback or "&free".
+     */
+    MHD_ContentReaderFreeCallback crfc;
+
+    /**
+     * Mutex to synchronize access to data/size and
+     * reference counts.
+     */
+    pthread_mutex_t mutex;
+
+    /**
+     * Reference count for this response.  Free
+     * once the counter hits zero.
+     */
+    unsigned int reference_count;
+
+    /**
+     * Set to -1 if size is not known.
+     */
+    size_t total_size;
+
+    /**
+     * Size of data.
+     */
+    size_t data_size;
+
+    /**
+     * Size of the data buffer.
+     */
+    size_t data_buffer_size;
+
+    /**
+     * At what offset in the stream is the
+     * beginning of data located?
+     */
+    size_t data_start;
+
+  };
 
 /**
  * States in a state machine for a connection.
@@ -175,419 +174,438 @@ struct MHD_Response
  * requires the write to be complete.
  */
 enum MHD_CONNECTION_STATE
-{
-  /**
-   * Connection just started (no headers received).
-   * Waiting for the line with the request type, URL and version.
-   */
-  MHD_CONNECTION_INIT = 0,
-
-  /**
-   * 1: We got the URL (and request type and version).  Wait for a header line.
-   */
-  MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1,
-
-  /**
-   * 2: We got part of a multi-line request header.  Wait for the rest.
-   */
-  MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1,
-
-  /**
-   * 3: We got the request headers.  Process them.
-   */
-  MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1,
-
-  /**
-   * 4: We have processed the request headers.  Send 100 continue.
-   */
-  MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
-
-  /**
-   * 5: We have processed the headers and need to send 100 CONTINUE.
-   */
-  MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1,
-
-  /**
-   * 6: We have sent 100 CONTINUE (or do not need to).  Read the message body.
-   */
-  MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1,
-
-  /**
-   * 7: We got the request body.  Wait for a line of the footer.
-   */
-  MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1,
-
-  /**
-   * 8: We got part of a line of the footer.  Wait for the
-   * rest.
-   */
-  MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1,
-
-  /**
-   * 9: We received the entire footer.  Wait for a response to be queued
-   * and prepare the response headers.
-   */
-  MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1,
-
-  /**
-   * 10: We have prepared the response headers in the writ buffer.
-   * Send the response headers.
-   */
-  MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1,
-
-  /**
-   * 11: We have sent the response headers.  Get ready to send the body.
-   */
-  MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1,
-
-  /**
-   * 12: We are ready to send a part of a non-chunked body.  Send it.
-   */
-  MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1,
-
-  /**
-   * 13: We are waiting for the client to provide more
-   * data of a non-chunked body.
-   */
-  MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1,
-
-  /**
-   * 14: We are ready to send a chunk.
-   */
-  MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1,
-
-  /**
-   * 15: We are waiting for the client to provide a chunk of the body.
-   */
-  MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1,
-
-  /**
-   * 16: We have sent the response body. Prepare the footers.
-   */
-  MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1,
-
-  /**
-   * 17: We have prepared the response footer.  Send it.
-   */
-  MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1,
-
-  /**
-   * 18: We have sent the response footer.  Shutdown or restart.
-   */
-  MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1,
-
-  /**
-   * 19: This connection is closed (no more activity
-   * allowed).
-   */
-  MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1,
-
-};
+  {
+    /**
+     * Connection just started (no headers received).
+     * Waiting for the line with the request type, URL and version.
+     */
+    MHD_CONNECTION_INIT = 0,
+
+    /**
+     * 1: We got the URL (and request type and version).  Wait for a header line.
+     */
+    MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1,
+
+    /**
+     * 2: We got part of a multi-line request header.  Wait for the rest.
+     */
+    MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1,
+
+    /**
+     * 3: We got the request headers.  Process them.
+     */
+    MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1,
+
+    /**
+     * 4: We have processed the request headers.  Send 100 continue.
+     */
+    MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
+
+    /**
+     * 5: We have processed the headers and need to send 100 CONTINUE.
+     */
+    MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1,
+
+    /**
+     * 6: We have sent 100 CONTINUE (or do not need to).  Read the message body.
+     */
+    MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1,
+
+    /**
+     * 7: We got the request body.  Wait for a line of the footer.
+     */
+    MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1,
+
+    /**
+     * 8: We got part of a line of the footer.  Wait for the
+     * rest.
+     */
+    MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1,
+
+    /**
+     * 9: We received the entire footer.  Wait for a response to be queued
+     * and prepare the response headers.
+     */
+    MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1,
+
+    /**
+     * 10: We have prepared the response headers in the writ buffer.
+     * Send the response headers.
+     */
+    MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1,
+
+    /**
+     * 11: We have sent the response headers.  Get ready to send the body.
+     */
+    MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1,
+
+    /**
+     * 12: We are ready to send a part of a non-chunked body.  Send it.
+     */
+    MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1,
+
+    /**
+     * 13: We are waiting for the client to provide more
+     * data of a non-chunked body.
+     */
+    MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1,
+
+    /**
+     * 14: We are ready to send a chunk.
+     */
+    MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1,
+
+    /**
+     * 15: We are waiting for the client to provide a chunk of the body.
+     */
+    MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1,
+
+    /**
+     * 16: We have sent the response body. Prepare the footers.
+     */
+    MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1,
+
+    /**
+     * 17: We have prepared the response footer.  Send it.
+     */
+    MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1,
+
+    /**
+     * 18: We have sent the response footer.  Shutdown or restart.
+     */
+    MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1,
+
+    /**
+     * 19: This connection is closed (no more activity
+     * allowed).
+     */
+    MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1,
+
+  };
+
+enum MHDS_CONNECTION_STATE
+  {
+    MHDS_CONNECTION_INIT = 0,
+
+    /**
+     * 1: We got the URL (and request type and version).  Wait for a header line.
+     */
+    MHDS_HANDSHAKE_COMPLETE = MHDS_CONNECTION_INIT + 1,
+
+    MHDS_CONNECTION_CONTINUE_SENDING = MHDS_HANDSHAKE_COMPLETE + 1,
+
+    MHDS_CONNECTION_CLOSED = MHDS_CONNECTION_CONTINUE_SENDING + 1
+  };
 
 struct MHD_Connection
-{
-
-  /**
-   * This is a linked list.
-   */
-  struct MHD_Connection *next;
-
-  /**
-   * Reference to the MHD_Daemon struct.
-   */
-  struct MHD_Daemon *daemon;
-
-  /**
-   * Linked list of parsed headers.
-   */
-  struct MHD_HTTP_Header *headers_received;
-
-  /**
-   * Response to transmit (initially NULL).
-   */
-  struct MHD_Response *response;
-
-  /**
-   * The memory pool is created whenever we first read
-   * from the TCP stream and destroyed at the end of
-   * each request (and re-created for the next request).
-   * In the meantime, this pointer is NULL.  The
-   * pool is used for all connection-related data
-   * except for the response (which maybe shared between
-   * connections) and the IP address (which persists
-   * across individual requests).
-   */
-  struct MemoryPool *pool;
-
-  /**
-   * We allow the main application to associate some
-   * pointer with the connection.  Here is where we
-   * store it.  (MHD does not know or care what it
-   * is).
-   */
-  void *client_context;
-
-  /**
-   * Request method.  Should be GET/POST/etc.  Allocated
-   * in pool.
-   */
-  char *method;
-
-  /**
-   * Requested URL (everything after "GET" only).  Allocated
-   * in pool.
-   */
-  char *url;
-
-  /**
-   * HTTP version string (i.e. http/1.1).  Allocated
-   * in pool.
-   */
-  char *version;
-
-  /**
-   * Buffer for reading requests.   Allocated
-   * in pool.  Actually one byte larger than
-   * read_buffer_size (if non-NULL) to allow for
-   * 0-termination.
-   */
-  char *read_buffer;
-
-  /**
-   * Buffer for writing response (headers only).  Allocated
-   * in pool.
-   */
-  char *write_buffer;
-
-  /**
-   * Last incomplete header line during parsing of headers.
-   * Allocated in pool.  Only valid if state is
-   * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
-   */
-  char *last;
-
-  /**
-   * Position after the colon on the last incomplete header
-   * line during parsing of headers.
-   * Allocated in pool.  Only valid if state is
-   * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
-   */
-  char *colon;
-
-  /**
-   * Foreign address (of length addr_len).  MALLOCED (not
-   * in pool!).
-   */
-  struct sockaddr_in *addr;
-
-  /**
-   * Thread for this connection (if we are using
-   * one thread per connection).
-   */
-  pthread_t pid;
-
-  /**
-   * Size of read_buffer (in bytes).  This value indicates
-   * how many bytes we're willing to read into the buffer;
-   * the real buffer is one byte longer to allow for
-   * adding zero-termination (when needed).
-   */
-  size_t read_buffer_size;
-
-  /**
-   * Position where we currently append data in
-   * read_buffer (last valid position).
-   */
-  size_t read_buffer_offset;
-
-  /**
-   * Size of write_buffer (in bytes).
-   */
-  size_t write_buffer_size;
-
-  /**
-   * Offset where we are with sending from write_buffer.
-   */
-  size_t write_buffer_send_offset;
-
-  /**
-   * Last valid location in write_buffer (where do we
-   * append and up to where is it safe to send?)
-   */
-  size_t write_buffer_append_offset;
-
-  /**
-   * How many more bytes of the body do we expect
-   * to read? "-1" for unknown.
-   */
-  size_t remaining_upload_size;
-
-  /**
-   * Current write position in the actual response
-   * (excluding headers, content only; should be 0
-   * while sending headers).
-   */
-  size_t response_write_position;
-
-  /**
-   * Position in the 100 CONTINUE message that
-   * we need to send when receiving http 1.1 requests.
-   */
-  size_t continue_message_write_offset;
-
-  /**
-   * Length of the foreign address.
-   */
-  socklen_t addr_len;
-
-  /**
-   * Last time this connection had any activity
-   * (reading or writing).
-   */
-  time_t last_activity;
-
-  /**
-   * Socket for this connection.  Set to -1 if
-   * this connection has died (daemon should clean
-   * up in that case).
-   */
-  int socket_fd;
-
-  /**
-   * Has this socket been closed for reading (i.e.
-   * other side closed the connection)?  If so,
-   * we must completely close the connection once
-   * we are done sending our response (and stop
-   * trying to read from this socket).
-   */
-  int read_closed;
-
-  /**
-   * State in the FSM for this connection.
-   */
-  enum MHD_CONNECTION_STATE state;
-
-  /**
-   * HTTP response code.  Only valid if response object
-   * is already set.
-   */
-  unsigned int responseCode;
-
-  /**
-   * Set to MHD_YES if the response's content reader
-   * callback failed to provide data the last time
-   * we tried to read from it.  In that case, the
-   * write socket should be marked as unready until
-   * the CRC call succeeds.
-   */
-  int response_unready;
-
-  /**
-   * Are we sending with chunked encoding?
-   */
-  int have_chunked_response;
-
-  /**
-   * Are we receiving with chunked encoding?  This will be set to
-   * MHD_YES after we parse the headers and are processing the body
-   * with chunks.  After we are done with the body and we are
-   * processing the footers; once the footers are also done, this will
-   * be set to MHD_NO again (before the final call to the handler).
-   */
-  int have_chunked_upload;
-
-  /**
-   * If we are receiving with chunked encoding, where are we right
-   * now?  Set to 0 if we are waiting to receive the chunk size;
-   * otherwise, this is the size of the current chunk.  A value of
-   * zero is also used when we're at the end of the chunks.
-   */
-  unsigned int current_chunk_size;
-
-  /**
-   * If we are receiving with chunked encoding, where are we currently
-   * with respect to the current chunk (at what offset / position)?
-   */
-  unsigned int current_chunk_offset;
-
-};
-
-
+  {
+
+    /**
+     * This is a linked list.
+     */
+    struct MHD_Connection *next;
+
+    /**
+     * Reference to the MHD_Daemon struct.
+     */
+    struct MHD_Daemon *daemon;
+
+    /**
+     * Linked list of parsed headers.
+     */
+    struct MHD_HTTP_Header *headers_received;
+
+    /**
+     * Response to transmit (initially NULL).
+     */
+    struct MHD_Response *response;
+
+    /**
+     * The memory pool is created whenever we first read
+     * from the TCP stream and destroyed at the end of
+     * each request (and re-created for the next request).
+     * In the meantime, this pointer is NULL.  The
+     * pool is used for all connection-related data
+     * except for the response (which maybe shared between
+     * connections) and the IP address (which persists
+     * across individual requests).
+     */
+    struct MemoryPool *pool;
+
+    /**
+     * We allow the main application to associate some
+     * pointer with the connection.  Here is where we
+     * store it.  (MHD does not know or care what it
+     * is).
+     */
+    void *client_context;
+
+    /**
+     * Request method.  Should be GET/POST/etc.  Allocated
+     * in pool.
+     */
+    char *method;
+
+    /**
+     * Requested URL (everything after "GET" only).  Allocated
+     * in pool.
+     */
+    char *url;
+
+    /**
+     * HTTP version string (i.e. http/1.1).  Allocated
+     * in pool.
+     */
+    char *version;
+
+    /**
+     * Buffer for reading requests.   Allocated
+     * in pool.  Actually one byte larger than
+     * read_buffer_size (if non-NULL) to allow for
+     * 0-termination.
+     */
+    char *read_buffer;
+
+    /**
+     * Buffer for writing response (headers only).  Allocated
+     * in pool.
+     */
+    char *write_buffer;
+
+    /**
+     * Last incomplete header line during parsing of headers.
+     * Allocated in pool.  Only valid if state is
+     * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
+     */
+    char *last;
+
+    /**
+     * Position after the colon on the last incomplete header
+     * line during parsing of headers.
+     * Allocated in pool.  Only valid if state is
+     * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
+     */
+    char *colon;
+
+    /**
+     * Foreign address (of length addr_len).  MALLOCED (not
+     * in pool!).
+     */
+    struct sockaddr_in *addr;
+
+    /**
+     * Thread for this connection (if we are using
+     * one thread per connection).
+     */
+    pthread_t pid;
+
+    /**
+     * Size of read_buffer (in bytes).  This value indicates
+     * how many bytes we're willing to read into the buffer;
+     * the real buffer is one byte longer to allow for
+     * adding zero-termination (when needed).
+     */
+    size_t read_buffer_size;
+
+    /**
+     * Position where we currently append data in
+     * read_buffer (last valid position).
+     */
+    size_t read_buffer_offset;
+
+    /**
+     * Size of write_buffer (in bytes).
+     */
+    size_t write_buffer_size;
+
+    /**
+     * Offset where we are with sending from write_buffer.
+     */
+    size_t write_buffer_send_offset;
+
+    /**
+     * Last valid location in write_buffer (where do we
+     * append and up to where is it safe to send?)
+     */
+    size_t write_buffer_append_offset;
+
+    /**
+     * How many more bytes of the body do we expect
+     * to read? "-1" for unknown.
+     */
+    size_t remaining_upload_size;
+
+    /**
+     * Current write position in the actual response
+     * (excluding headers, content only; should be 0
+     * while sending headers).
+     */
+    size_t response_write_position;
+
+    /**
+     * Position in the 100 CONTINUE message that
+     * we need to send when receiving http 1.1 requests.
+     */
+    size_t continue_message_write_offset;
+
+    /**
+     * Length of the foreign address.
+     */
+    socklen_t addr_len;
+
+    /**
+     * Last time this connection had any activity
+     * (reading or writing).
+     */
+    time_t last_activity;
+
+    /**
+     * Socket for this connection.  Set to -1 if
+     * this connection has died (daemon should clean
+     * up in that case).
+     */
+    int socket_fd;
+
+    /**
+     * Has this socket been closed for reading (i.e.
+     * other side closed the connection)?  If so,
+     * we must completely close the connection once
+     * we are done sending our response (and stop
+     * trying to read from this socket).
+     */
+    int read_closed;
+
+    /**
+     * State in the FSM for this connection.
+     */
+    enum MHD_CONNECTION_STATE state;
+
+    /**
+     * HTTP response code.  Only valid if response object
+     * is already set.
+     */
+    unsigned int responseCode;
+
+    /**
+     * Set to MHD_YES if the response's content reader
+     * callback failed to provide data the last time
+     * we tried to read from it.  In that case, the
+     * write socket should be marked as unready until
+     * the CRC call succeeds.
+     */
+    int response_unready;
+
+    /**
+     * Are we sending with chunked encoding?
+     */
+    int have_chunked_response;
+
+    /**
+     * Are we receiving with chunked encoding?  This will be set to
+     * MHD_YES after we parse the headers and are processing the body
+     * with chunks.  After we are done with the body and we are
+     * processing the footers; once the footers are also done, this will
+     * be set to MHD_NO again (before the final call to the handler).
+     */
+    int have_chunked_upload;
+
+    /**
+     * If we are receiving with chunked encoding, where are we right
+     * now?  Set to 0 if we are waiting to receive the chunk size;
+     * otherwise, this is the size of the current chunk.  A value of
+     * zero is also used when we're at the end of the chunks.
+     */
+    unsigned int current_chunk_size;
+
+    /**
+     * If we are receiving with chunked encoding, where are we currently
+     * with respect to the current chunk (at what offset / position)?
+     */
+    unsigned int current_chunk_offset;
+
+  };
+
+typedef struct MHD_Connection MHD_Connection_t;
 
 struct MHD_Daemon
-{
-
-  /**
-   * Callback function for all requests.
-   */
-  MHD_AccessHandlerCallback default_handler;
-
-  /**
-   * Closure argument to default_handler.
-   */
-  void *default_handler_cls;
-
-  /**
-   * Linked list of our current connections.
-   */
-  struct MHD_Connection *connections;
-
-  MHD_AcceptPolicyCallback apc;
-
-  void *apc_cls;
-
-  MHD_RequestCompletedCallback notify_completed;
-
-  void *notify_completed_cls;
-
-  /**
-   * PID of the select thread (if we have internal select)
-   */
-  pthread_t pid;
-
-  /**
-   * Listen socket.
-   */
-  int socket_fd;
-
-  /**
-   * Are we shutting down?
-   */
-  int shutdown;
-
-  /**
-   * Size of the per-connection memory pools.
-   */
-  unsigned int pool_size;
-
-  /**
-   * Limit on the number of parallel connections.
-   */
-  unsigned int max_connections;
-
-  /**
-   * After how many seconds of inactivity should
-   * connections time out?  Zero for no timeout.
-   */
-  unsigned int connection_timeout;
-
-  /**
-   * Maximum number of connections per IP, or 0 for
-   * unlimited.
-   */
-  unsigned int per_ip_connection_limit;
-
-  /**
-   * Daemon's options.
-   */
-  enum MHD_OPTION options;
-
-  /**
-   * Listen port.
-   */
-  unsigned short port;
-
-};
-
+  {
+
+    /**
+     * Callback function for all requests.
+     */
+    MHD_AccessHandlerCallback default_handler;
+
+    /**
+     * Closure argument to default_handler.
+     */
+    void *default_handler_cls;
+
+    /**
+     * Linked list of our current connections.
+     */
+    struct MHD_Connection *connections;
+
+    /**
+     * Linked list of our current connections.
+     */
+    // TODO switch to a dedicated tls connection struct 
+    struct MHD_Connection *tls_connections;
+
+    MHD_AcceptPolicyCallback apc;
+
+    void *apc_cls;
+
+    MHD_RequestCompletedCallback notify_completed;
+
+    void *notify_completed_cls;
+
+    /**
+     * PID of the select thread (if we have internal select)
+     */
+    pthread_t pid;
+
+    /**
+     * Listen socket.
+     */
+    int socket_fd;
+
+    /**
+     * Are we shutting down?
+     */
+    int shutdown;
+
+    /**
+     * Size of the per-connection memory pools.
+     */
+    unsigned int pool_size;
+
+    /**
+     * Limit on the number of parallel connections.
+     */
+    unsigned int max_connections;
+
+    /**
+     * After how many seconds of inactivity should
+     * connections time out?  Zero for no timeout.
+     */
+    unsigned int connection_timeout;
+
+    /**
+     * Maximum number of connections per IP, or 0 for
+     * unlimited.
+     */
+    unsigned int per_ip_connection_limit;
+
+    /**
+     * Daemon's options.
+     */
+    enum MHD_OPTION options;
+
+    /**
+     * Listen port.
+     */
+    unsigned short port;
+
+  };
 
 #endif

+ 29 - 3
src/examples/Makefile.am

@@ -1,10 +1,16 @@
 SUBDIRS  = .
 
-INCLUDES = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/src/include 
 
 # example programs
 
-noinst_PROGRAMS = minimal_example querystring_example fileserver_example fileserver_example_external_select
+noinst_PROGRAMS = \
+https_server_example \
+https_echo_client_example \
+minimal_example \
+querystring_example \
+fileserver_example \
+fileserver_example_external_select
 
 minimal_example_SOURCES = \
  minimal_example.c 
@@ -21,9 +27,29 @@ fileserver_example_SOURCES = \
 fileserver_example_LDADD = \
  $(top_builddir)/src/daemon/libmicrohttpd.la 
 
-
 fileserver_example_external_select_SOURCES = \
  fileserver_example_external_select.c 
 fileserver_example_external_select_LDADD = \
  $(top_builddir)/src/daemon/libmicrohttpd.la 
 
+https_server_example_CPPFLAGS = \
+ $(GNUTLS_CPPFLAGS) \
+ -I$(top_srcdir)/src/daemon
+https_server_example_SOURCES = \
+ https_server_example.c
+https_server_example_LDADD = \
+ $(top_builddir)/src/daemon/libmicrohttpd.la
+https_server_example_LDFLAGS = \
+ -L$(GNUTLS_LIB_PATH) \
+ -lgnutls
+ 
+https_echo_client_example_CPPFLAGS = \
+ $(GNUTLS_CPPFLAGS) \
+ -I$(top_srcdir)/src/daemon
+https_echo_client_example_SOURCES = \
+ https_echo_client_example.c
+https_echo_client_example_LDADD = \
+ $(top_builddir)/src/daemon/libmicrohttpd.la
+https_echo_client_example_LDFLAGS = \
+ -L$(GNUTLS_LIB_PATH) \
+ -lgnutls

+ 153 - 0
src/examples/https_echo_client_example.c

@@ -0,0 +1,153 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2007 Christian Grothoff
+
+ libmicrohttpd 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 2, or (at your
+ option) any later version.
+
+ libmicrohttpd 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 libmicrohttpd; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file https_echo_client.c
+ * @brief a simple echo client to use in conjuction with the echo TLS server. 
+ * @author LV-426
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <gnutls/gnutls.h>
+
+#define MAX_BUF 1024
+#define SA struct sockaddr
+#define MSG "GET / HTTP/1.0\r\n\r\n"
+
+extern int tcp_connect (void);
+extern void tcp_close (int sd);
+
+int
+main (int argc, char **argv)
+{
+  int ret, sd, ii, err;
+  gnutls_session_t session;
+  char buffer[MAX_BUF + 1];
+  gnutls_anon_client_credentials_t anoncred;
+
+  struct sockaddr_in servaddr4;
+  const struct sockaddr *servaddr;
+  struct sockaddr_in sa;
+  socklen_t addrlen;
+
+  if (argc < 2)
+    {
+      printf ("Usage : %s SERVER-PORT\n", argv[0]);
+      return 1;
+    }
+
+  gnutls_global_init ();
+
+  gnutls_anon_allocate_client_credentials (&anoncred);
+
+  /* Initialize TLS session */
+  gnutls_init (&session, GNUTLS_CLIENT);
+
+  /* Use default priorities */
+  gnutls_priority_set_direct (session, "PERFORMANCE:+ANON-DH:!ARCFOUR-128",
+                              NULL);
+
+  /* put the anonymous credentials to the current session */
+  gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
+
+  sd = socket (AF_INET, SOCK_STREAM, 0);
+  memset (&sa, '\0', sizeof (sa));
+  sa.sin_family = AF_INET;
+  sa.sin_port = htons (atoi (argv[1]));
+  inet_pton (AF_INET, "127.0.0.1", &sa.sin_addr);
+
+  /* connect to the peer */
+  err = connect (sd, (struct sockaddr *) &sa, sizeof (sa));
+  if (err < 0)
+    {
+      fprintf (stderr, "Connect error\n");
+      exit (1);
+    }
+
+  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
+
+  /* Perform the TLS handshake */
+  ret = gnutls_handshake (session);
+
+  if (ret < 0)
+    {
+      fprintf (stderr, "*** Handshake failed\n");
+      gnutls_perror (ret);
+      goto end;
+    }
+  else
+    {
+      printf ("- Handshake was completed\n");
+    }
+
+  for (;;)
+    {
+       /**/ scanf ("%s", buffer);
+
+      if (strcmp (buffer, "exit") == 0)
+        {
+          gnutls_record_send (session, buffer, strlen (MSG));
+          break;
+        }
+      gnutls_record_send (session, buffer, strlen (MSG));
+
+      ret = gnutls_record_recv (session, buffer, MAX_BUF);
+      if (ret == 0)
+        {
+          printf ("- Peer has closed the TLS connection\n");
+          goto end;
+        }
+      else if (ret < 0)
+        {
+          fprintf (stderr, "*** Error: %s\n", gnutls_strerror (ret));
+          break;
+        }
+
+      printf ("- Received %d bytes: ", ret);
+      for (ii = 0; ii < ret; ii++)
+        {
+          fputc (buffer[ii], stdout);
+        }
+      fputs ("\n", stdout);
+    }
+
+end:
+
+  shutdown (sd, SHUT_RDWR);
+  close (sd);
+
+  gnutls_deinit (session);
+
+  gnutls_anon_free_client_credentials (anoncred);
+
+  gnutls_global_deinit ();
+
+  return 0;
+}

+ 182 - 0
src/examples/https_server_example.c

@@ -0,0 +1,182 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2007 Christian Grothoff
+
+ libmicrohttpd 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 2, or (at your
+ option) any later version.
+
+ libmicrohttpd 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 libmicrohttpd; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file https_server_example.c
+ * @brief a simple echo server using TLS. echo input from client until 'exit' message is received. 
+ * @author LV-426
+ */
+
+#include "config.h"
+#include <microhttpd.h>
+#include "internal.h"
+
+#include <stdlib.h>
+#ifndef MINGW
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <gnutls/gnutls.h>
+
+#define DH_BITS 1024
+#define MAX_BUF 1024
+/* server credintials */
+gnutls_anon_server_credentials_t anoncred;
+
+/* server Diffie-Hellman parameters */
+static gnutls_dh_params_t dh_params;
+
+
+/* Generate Diffie Hellman parameters - for use with DHE kx algorithms. */
+static int
+generate_dh_params (void)
+{
+
+  gnutls_dh_params_init (&dh_params);
+  gnutls_dh_params_generate2 (dh_params, DH_BITS);
+  return 0;
+}
+
+gnutls_session_t
+initialize_tls_session (void)
+{
+  gnutls_session_t session;
+
+  gnutls_init (&session, GNUTLS_SERVER);
+
+  gnutls_priority_set_direct (session, "NORMAL:+ANON-DH", NULL);
+
+  gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
+
+  gnutls_dh_set_prime_bits (session, DH_BITS);
+
+  return session;
+}
+
+/* Accept Policy Callback */
+static int
+TLS_echo (void *cls,
+          struct MHD_Connection *connection,
+          const char *url,
+          const char *method,
+          const char *upload_data,
+          const char *version, unsigned int *upload_data_size, void **ptr)
+{
+  gnutls_session_t session;
+  static int aptr;
+  struct MHD_Response *response;
+  char buffer[MAX_BUF + 1];
+  int ret;
+
+  printf ("accepted connection from %d\n", connection->addr->sin_addr);
+
+  session = initialize_tls_session ();
+
+  gnutls_transport_set_ptr (session, connection->socket_fd);
+
+  ret = gnutls_handshake (session);
+  if (ret < 0)
+    {
+      /* set connection as closed */
+      connection->socket_fd = 1;
+      gnutls_deinit (session);
+      fprintf (stderr, "*** Handshake has failed (%s)\n\n",
+               gnutls_strerror (ret));
+      return MHD_NO;
+    }
+
+  printf ("TLS Handshake completed\n");
+  connection->state = MHDS_HANDSHAKE_COMPLETE;
+
+  /* simple echo loop. message encryption/decryption is acheived through 'gnutls_record_send'
+   *  & gnutls_record_recv calls. */
+  for (;;)
+    {
+      memset (buffer, 0, MAX_BUF + 1);
+      ret = gnutls_record_recv (session, buffer, MAX_BUF);
+
+      if (ret < 0)
+        {
+          fprintf (stderr, "\n*** Received corrupted "
+                   "data(%d). Closing the connection.\n\n", ret);
+          break;
+        }
+      else if (ret >= 0)
+        {
+          if (strcmp (buffer, "exit") == 0)
+            {
+              printf ("\n- Peer has closed the GNUTLS connection\n");
+              break;
+            }
+          else
+            {
+              /* echo data back to the client */
+              gnutls_record_send (session, buffer, strlen (buffer));
+            }
+        }
+    }
+  printf ("\n");
+
+  /* mark connection as closed */
+  connection->socket_fd = -1;
+
+  gnutls_deinit (session);
+
+  return ret;
+}
+
+int
+main (int argc, char *const *argv)
+{
+  struct MHD_Daemon *daemon;
+  struct MHD_Daemon *TLS_daemon;
+
+  /* look for HTTPS port argument */
+  if (argc < 4)
+    {
+      printf ("Usage : %s HTTP-PORT SECONDS-TO-RUN HTTPS-PORT\n", argv[0]);
+      return 1;
+    }
+
+  gnutls_global_init ();
+
+  gnutls_anon_allocate_server_credentials (&anoncred);
+
+  generate_dh_params ();
+
+  gnutls_anon_set_server_dh_params (anoncred, dh_params);
+
+  TLS_daemon = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
+                                  | MHD_USE_DEBUG | MHD_USE_SSL,
+                                  atoi (argv[3]), NULL, NULL, &TLS_echo, NULL,
+                                  MHD_OPTION_END);
+
+  if (TLS_daemon == NULL)
+    return 1;
+  sleep (atoi (argv[2]));
+
+  MHD_stop_daemon (daemon);
+
+  gnutls_anon_free_server_credentials (anoncred);
+
+  gnutls_global_deinit ();
+  return 0;
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов