⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpd.c

📁 在luminary平台下移植lwip到freertos,集成开发环境KEIL
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
 * 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
 *
 * This file is part of the lwIP TCP/IP stack.
 *
 * Author: Adam Dunkels <adam@sics.se>
 *
 */

/* This file is modified from the original version (httpd.c) as shipped with
 * lwIP version 1.3.0. Changes have been made to allow support for a
 * rudimentary server-side-include facility which will replace tags of the form
 * <!--#tag--> in any file whose extension is .shtml, .shtm or .ssi with
 * strings provided by an include handler whose pointer is provided to the
 * module via function http_set_ssi_handler(). Additionally, a simple common
 * gateway interface (CGI) handling mechanism has been added to allow clients
 * to hook functions to particular request URIs.
 *
 * To enable SSI support, define label INCLUDE_HTTPD_SSI in lwipopts.h.
 * To enable CGI support, define label INCLUDE_HTTPD_CGI in lwipopts.h.
 *
 * By default, the server assumes that HTTP headers are already present in
 * each file stored in the file system.  By defining DYNAMIC_HTTP_HEADERS in
 * lwipopts.h, this behavior can be changed such that the server inserts the
 * headers automatically based on the extension of the file being served.  If
 * this mode is used, be careful to ensure that the file system image used
 * does not already contain the header information.
 *
 * File system images without headers can be created using the makefsfile
 * tool with the -h command line option.
 */

/*
 * Notes about valid SSI tags
 * --------------------------
 *
 * The following assumptions are made about tags used in SSI markers:
 *
 * 1. No tag may contain '-' or whitespace characters within the tag name.
 * 2. Whitespace is allowed between the tag leadin "<!--#" and the start of
 *    the tag name and between the tag name and the leadout string "-->".
 * 3. The maximum tag name length is MAX_TAG_NAME_LEN, currently 8 characters.
 *
 * Notes on CGI usage
 * ------------------
 *
 * The simple CGI support offered here works with GET method requests only
 * and can handle up to 16 parameters encoded into the URI. The handler
 * function may not write directly to the HTTP output but must return a
 * filename that the HTTP server will send to the browser as a response to
 * the incoming CGI request.
 *
 */
#include "lwip/debug.h"

#include "lwip/stats.h"

#include "httpd.h"

#include "lwip/tcp.h"

#include "fs.h"

#include <string.h>
#include "ustdlib.h"


#ifdef INCLUDE_HTTPD_DEBUG
#include "hw_types.h"
#include "utils/uartstdio.h"
#define DEBUG_PRINT UARTprintf
#else
#define DEBUG_PRINT while(0)((int (*)(char *, ...))0)
#endif

#ifndef true
#define true ((u8_t)1)
#endif

#ifndef false
#define false ((u8_t)0)
#endif

typedef struct
{
    const char *name;
    u8_t shtml;
} default_filename;

const default_filename g_psDefaultFilenames[] = {
  {"/index.shtml", true },
  {"/index.ssi", true },
  {"/index.shtm", true },
  {"/index.html", false },
  {"/index.htm", false }
};

#define NUM_DEFAULT_FILENAMES (sizeof(g_psDefaultFilenames) /                 \
                               sizeof(default_filename))

#ifdef DYNAMIC_HTTP_HEADERS
/* The number of individual strings that comprise the headers sent before each
 * requested file.
 */
#define NUM_FILE_HDR_STRINGS 3
#endif

#ifdef INCLUDE_HTTPD_SSI
const char *g_pcSSIExtensions[] = {
  ".shtml", ".shtm", ".ssi"
};

#define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *))

enum tag_check_state {
    TAG_NONE,       /* Not processing an SSI tag */
    TAG_LEADIN,     /* Tag lead in "<!--#" being processed */
    TAG_FOUND,      /* Tag name being read, looking for lead-out start */
    TAG_LEADOUT,    /* Tag lead out "-->" being processed */
    TAG_SENDING     /* Sending tag replacement string */
};
#endif /* INCLUDE_HTTPD_SSI */

struct http_state {
  struct fs_file *handle;
  char *file;       /* Pointer to first unsent byte in buf. */
  char *buf;        /* File read buffer. */
#ifdef INCLUDE_HTTPD_SSI
  char *parsed;     /* Pointer to the first unparsed byte in buf. */
  char *tag_end;    /* Pointer to char after the closing '>' of the tag. */
  u32_t parse_left; /* Number of unparsed bytes in buf. */
#endif
  u32_t left;       /* Number of unsent bytes in buf. */
  int buf_len;      /* Size of file read buffer, buf. */
  u8_t retries;
#ifdef INCLUDE_HTTPD_SSI
  u8_t tag_check;   /* true if we are processing a .shtml file else false */
  u8_t tag_index;   /* Counter used by tag parsing state machine */
  u8_t tag_insert_len; /* Length of insert in string tag_insert */
  u8_t tag_name_len; /* Length of the tag name in string tag_name */
  char tag_name[MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */
  char tag_insert[MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */
  enum tag_check_state tag_state; /* State of the tag processor */
#endif
#ifdef INCLUDE_HTTPD_CGI
  char *params[MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
  char *param_vals[MAX_CGI_PARAMETERS]; /* Values for each extracted param */
#endif
#ifdef DYNAMIC_HTTP_HEADERS
  const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */
  u16_t hdr_pos;     /* The position of the first unsent header byte in the
                        current string */
  u16_t hdr_index;   /* The index of the hdr string currently being sent. */
#endif
};

#ifdef INCLUDE_HTTPD_SSI
/* SSI insert handler function pointer. */
tSSIHandler g_pfnSSIHandler = NULL;
int g_iNumTags = 0;
const char **g_ppcTags = NULL;

#define LEN_TAG_LEAD_IN 5
const char * const g_pcTagLeadIn = "<!--#";

#define LEN_TAG_LEAD_OUT 3
const char * const g_pcTagLeadOut = "-->";
#endif /* INCLUDE_HTTPD_SSI */

#ifdef INCLUDE_HTTPD_CGI
/* CGI handler information */
const tCGI *g_pCGIs = NULL;
int g_iNumCGIs = 0;
#endif /* INCLUDE_HTTPD_CGI */

#ifdef DYNAMIC_HTTP_HEADERS
//*****************************************************************************
//
// HTTP header strings for various filename extensions.
//
//*****************************************************************************
typedef struct
{
    const char *pszExtension;
    unsigned long ulHeaderIndex;
} tHTTPHeader;

const char *g_psHTTPHeaderStrings[] =
{
 "Content-type: text/html\r\n\r\n",
 "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\n"    \
   "Pragma: no-cache\r\n\r\n",
 "Content-type: image/gif\r\n\r\n",
 "Content-type: image/png\r\n\r\n",
 "Content-type: image/jpeg\r\n\r\n",
 "Content-type: image/bmp\r\n\r\n",
 "Content-type: application/octet-stream\r\n\r\n",
 "Content-type: application/x-javascript\r\n\r\n",
 "Content-type: audio/x-pn-realaudio\r\n\r\n",
 "Content-type: text/css\r\n\r\n",
 "Content-type: text/plain\r\n\r\n",
 "HTTP/1.0 200 OK\r\n",
 "HTTP/1.0 404 File not found\r\n",
 "Server: lwIP/1.3.0 (http://www.sics.se/~adam/lwip/)\r\n",
 "\r\n<html><body><h2>404: The requested file cannot be found."             \
   "</h2></body></html>\r\n"
};

#define HTTP_HDR_HTML           0
#define HTTP_HDR_SSI            1
#define HTTP_HDR_GIF            2
#define HTTP_HDR_JPG            3
#define HTTP_HDR_PNG            4
#define HTTP_HDR_BMP            5
#define HTTP_HDR_APP            6
#define HTTP_HDR_JS             7
#define HTTP_HDR_RA             8
#define HTTP_HDR_CSS            9
#define HTTP_HDR_DEFAULT_TYPE   10
#define HTTP_HDR_OK             11
#define HTTP_HDR_NOT_FOUND      12
#define HTTP_HDR_SERVER         13
#define DEFAULT_404_HTML        14

tHTTPHeader g_psHTTPHeaders[] =
{
 { "html", HTTP_HDR_HTML},
 { "htm",  HTTP_HDR_HTML},
 { "shtml",HTTP_HDR_SSI},
 { "shtm", HTTP_HDR_SSI},
 { "ssi",  HTTP_HDR_SSI},
 { "gif",  HTTP_HDR_GIF},
 { "png",  HTTP_HDR_PNG},
 { "jpg",  HTTP_HDR_JPG},
 { "bmp",  HTTP_HDR_BMP},
 { "class",HTTP_HDR_APP},
 { "cls",  HTTP_HDR_APP},
 { "js",   HTTP_HDR_JS},
 { "ram",  HTTP_HDR_RA},
 { "css",  HTTP_HDR_CSS}
};

#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader))

#endif

/*-----------------------------------------------------------------------------------*/
static void
conn_err(void *arg, err_t err)
{
  struct http_state *hs;

  LWIP_UNUSED_ARG(err);

  if(arg)
  {
      hs = arg;
      if(hs->handle) {
        fs_close(hs->handle);
        hs->handle = NULL;
      }
      if(hs->buf)
      {
          mem_free(hs->buf);
      }
      mem_free(hs);
  }
}
/*-----------------------------------------------------------------------------------*/
static void
close_conn(struct tcp_pcb *pcb, struct http_state *hs)
{
  err_t err;
  DEBUG_PRINT("Closing connection 0x%08x\n", pcb);

  tcp_arg(pcb, NULL);
  tcp_sent(pcb, NULL);
  tcp_recv(pcb, NULL);
  if(hs->handle) {
    fs_close(hs->handle);
    hs->handle = NULL;
  }
  if(hs->buf)
  {
    mem_free(hs->buf);
  }
  mem_free(hs);
  err = tcp_close(pcb);
  if(err != ERR_OK)
  {
      DEBUG_PRINT("Error %d closing 0x%08x\n", err, pcb);
  }
}
/*-----------------------------------------------------------------------------------*/
#ifdef INCLUDE_HTTPD_CGI
static int
extract_uri_parameters(struct http_state *hs, char *params)
{
  char *pair;
  char *equals;
  int loop;

  /* If we have no parameters at all, return immediately. */
  if(!params || (params[0] == '\0')) {
      return(0);
  }

  /* Get a pointer to our first parameter */
  pair = params;

  /*
   * Parse up to MAX_CGI_PARAMETERS from the passed string and ignore the
   * remainder (if any)
   */
  for(loop = 0; (loop < MAX_CGI_PARAMETERS) && pair; loop++) {

    /* Save the name of the parameter */
    hs->params[loop] = pair;

    /* Remember the start of this name=value pair */
    equals = pair;

    /* Find the start of the next name=value pair and replace the delimiter
     * with a 0 to terminate the previous pair string.
     */
    pair = strchr(pair, '&');
    if(pair) {
      *pair = '\0';
      pair++;
    } else {
       /* We didn't find a new parameter so find the end of the URI and
        * replace the space with a '\0'
        */
        pair = strchr(equals, ' ');
        if(pair) {
            *pair = '\0';
        }

        /* Revert to NULL so that we exit the loop as expected. */
        pair = NULL;
    }

    /* Now find the '=' in the previous pair, replace it with '\0' and save
     * the parameter value string.
     */
    equals = strchr(equals, '=');
    if(equals) {
      *equals = '\0';
      hs->param_vals[loop] = equals + 1;
    } else {
      hs->param_vals[loop] = NULL;
    }
  }

  return(loop);
}
#endif /* INCLUDE_HTTPD_CGI */

/*-----------------------------------------------------------------------------------*/
#ifdef INCLUDE_HTTPD_SSI
static void
get_tag_insert(struct http_state *hs)
{
  int loop;

  if(g_pfnSSIHandler && g_ppcTags && g_iNumTags) {

    /* Find this tag in the list we have been provided. */
    for(loop = 0; loop < g_iNumTags; loop++)
    {
      if(strcmp(hs->tag_name, g_ppcTags[loop]) == 0) {
        hs->tag_insert_len = g_pfnSSIHandler(loop, hs->tag_insert,
                                             MAX_TAG_INSERT_LEN);
        return;
      }
    }
  }

  /* If we drop out, we were asked to serve a page which contains tags that
   * we don't have a handler for. Merely echo back the tags with an error
   * marker.
   */
  usnprintf(hs->tag_insert, MAX_TAG_INSERT_LEN + 1,
            "<b>***UNKNOWN TAG %s***</b>", hs->tag_name);
  hs->tag_insert_len = strlen(hs->tag_insert);
}
#endif /* INCLUDE_HTTPD_SSI */

#ifdef DYNAMIC_HTTP_HEADERS
//*****************************************************************************
//
// Generate the relevant HTTP headers for the given filename and write
// them into the supplied buffer.  Returns true on success or false on failure.
//
//*****************************************************************************
static void
get_http_headers(struct http_state *pState, char *pszURI)
{
    int iLoop;
    char *pszWork;
    char *pszExt;
    char *pszVars;

    //
    // Ensure that we initialize the loop counter.
    //
    iLoop = 0;


    //
    //
    // In all cases, the second header we send is the server identification
    // so set it here.
    //
    pState->hdrs[1] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER];

    // Is this a normal file or the special case we use to send back the
    // default "404: Page not found" response?
    //
    if(pszURI == NULL)
    {
        pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
        pState->hdrs[2] = g_psHTTPHeaderStrings[DEFAULT_404_HTML];

        //
        // Set up to send the first header string.
        //
        pState->hdr_index = 0;
        pState->hdr_pos = 0;
        return;
    }
    else
    {
        //
        // We are dealing with a particular filename. Look for one other
        // special case.  We assume that any filename with "404" in it must be
        // indicative of a 404 server error whereas all other files require
        // the 200 OK header.
        //
        if(ustrstr(pszURI, "404") || pszURI == NULL)
        {
            pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
        }
        else
        {
            pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_OK];
        }

        //
        // Determine if the URI has any variables and, if so, temporarily remove
        // them.
        //
        pszVars = strchr(pszURI, '?');
        if(pszVars)
        {
            *pszVars = '\0';
        }

        //

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -