httpd.c

来自「NXPl788上lwip的无操作系统移植,基于Embest开发板」· C语言 代码 · 共 1,866 行 · 第 1/5 页

C
1,866
字号
        } else {
          LWIP_DEBUGF(HTTPD_DEBUG, ("POST received invalid Content-Length: %s\n",
            conten_len_num));
          return ERR_ARG;
        }
      }
    }
  }
  /* if we come here, the POST is incomplete */
#if LWIP_HTTPD_SUPPORT_REQUESTLIST
  return ERR_INPROGRESS;
#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
  return ERR_ARG;
#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
}

#if LWIP_HTTPD_POST_MANUAL_WND
/** A POST implementation can call this function to update the TCP window.
 * This can be used to throttle data reception (e.g. when received data is
 * programmed to flash and data is received faster than programmed).
 *
 * @param connection A connection handle passed to httpd_post_begin for which
 *        httpd_post_finished has *NOT* been called yet!
 * @param recved_len Length of data received (for window update)
 */
void httpd_post_data_recved(void *connection, u16_t recved_len)
{
  struct http_state *hs = (struct http_state*)connection;
  if (hs != NULL) {
    if (hs->no_auto_wnd) {
      u16_t len = recved_len;
      if (hs->unrecved_bytes >= recved_len) {
        hs->unrecved_bytes -= recved_len;
      } else {
        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_LEVEL_WARNING, ("httpd_post_data_recved: recved_len too big\n"));
        len = (u16_t)hs->unrecved_bytes;
        hs->unrecved_bytes = 0;
      }
      if (hs->pcb != NULL) {
        if (len != 0) {
          tcp_recved(hs->pcb, len);
        }
        if ((hs->post_content_len_left == 0) && (hs->unrecved_bytes == 0)) {
          /* finished handling POST */
          http_handle_post_finished(hs);
          http_send_data(hs->pcb, hs);
        }
      }
    }
  }
}
#endif /* LWIP_HTTPD_POST_MANUAL_WND */

#endif /* LWIP_HTTPD_SUPPORT_POST */

/**
 * When data has been received in the correct state, try to parse it
 * as a HTTP request.
 *
 * @param p the received pbuf
 * @param hs the connection state
 * @param pcb the tcp_pcb which received this packet
 * @return ERR_OK if request was OK and hs has been initialized correctly
 *         ERR_INPROGRESS if request was OK so far but not fully received
 *         another err_t otherwise
 */
static err_t
http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb)
{
  char *data;
  char *crlf;
  u16_t data_len;
  struct pbuf *p = *inp;
#if LWIP_HTTPD_SUPPORT_REQUESTLIST
  u16_t clen;
#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
#if LWIP_HTTPD_SUPPORT_POST
  err_t err;
#endif /* LWIP_HTTPD_SUPPORT_POST */

  LWIP_UNUSED_ARG(pcb); /* only used for post */
  LWIP_ASSERT("p != NULL", p != NULL);
  LWIP_ASSERT("hs != NULL", hs != NULL);

  if ((hs->handle != NULL) || (hs->file != NULL)) {
    LWIP_DEBUGF(HTTPD_DEBUG, ("Received data while sending a file\n"));
    /* already sending a file */
    /* @todo: abort? */
    return ERR_USE;
  }

#if LWIP_HTTPD_SUPPORT_REQUESTLIST

  LWIP_DEBUGF(HTTPD_DEBUG, ("Received %"U16_F" bytes\n", p->tot_len));

  /* first check allowed characters in this pbuf? */

  /* enqueue the pbuf */
  if (hs->req == NULL) {
    LWIP_DEBUGF(HTTPD_DEBUG, ("First pbuf\n"));
    hs->req = p;
  } else {
    LWIP_DEBUGF(HTTPD_DEBUG, ("pbuf enqueued\n"));
    pbuf_cat(hs->req, p);
  }

  if (hs->req->next != NULL) {
    data_len = LWIP_MIN(hs->req->tot_len, LWIP_HTTPD_MAX_REQ_LENGTH);
    pbuf_copy_partial(hs->req, httpd_req_buf, data_len, 0);
    data = httpd_req_buf;
  } else
#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
  {
    data = (char *)p->payload;
    data_len = p->len;
    if (p->len != p->tot_len) {
      LWIP_DEBUGF(HTTPD_DEBUG, ("Warning: incomplete header due to chained pbufs\n"));
    }
  }

  /* received enough data for minimal request? */
  if (data_len >= MIN_REQ_LEN) {
    /* wait for CRLF before parsing anything */
    crlf = strnstr(data, CRLF, data_len);
    if (crlf != NULL) {
#if LWIP_HTTPD_SUPPORT_POST
      int is_post = 0;
#endif /* LWIP_HTTPD_SUPPORT_POST */
      int is_09 = 0;
      char *sp1, *sp2;
      u16_t left_len, uri_len;
      LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("CRLF received, parsing request\n"));
      /* parse method */
      if (!strncmp(data, "GET ", 4)) {
        sp1 = data + 3;
        /* received GET request */
        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received GET request\"\n"));
#if LWIP_HTTPD_SUPPORT_POST
      } else if (!strncmp(data, "POST ", 5)) {
        /* store request type */
        is_post = 1;
        sp1 = data + 4;
        /* received GET request */
        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received POST request\n"));
#endif /* LWIP_HTTPD_SUPPORT_POST */
      } else {
        /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
        data[4] = 0;
        /* unsupported method! */
        LWIP_DEBUGF(HTTPD_DEBUG, ("Unsupported request method (not implemented): \"%s\"\n",
          data));
        return http_find_error_file(hs, 501);
      }
      /* if we come here, method is OK, parse URI */
      left_len = data_len - ((sp1 +1) - data);
      sp2 = strnstr(sp1 + 1, " ", left_len);
#if LWIP_HTTPD_SUPPORT_V09
      if (sp2 == NULL) {
        /* HTTP 0.9: respond with correct protocol version */
        sp2 = strnstr(sp1 + 1, CRLF, left_len);
        is_09 = 1;
#if LWIP_HTTPD_SUPPORT_POST
        if (is_post) {
          /* HTTP/0.9 does not support POST */
          goto badrequest;
        }
#endif /* LWIP_HTTPD_SUPPORT_POST */
      }
#endif /* LWIP_HTTPD_SUPPORT_V09 */
      uri_len = sp2 - (sp1 + 1);
      if ((sp2 != 0) && (sp2 > sp1)) {
        char *uri = sp1 + 1;
        /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
        *sp1 = 0;
        uri[uri_len] = 0;
        LWIP_DEBUGF(HTTPD_DEBUG, ("Received \"%s\" request for URI: \"%s\"\n",
                    data, uri));
#if LWIP_HTTPD_SUPPORT_POST
        if (is_post) {
#if LWIP_HTTPD_SUPPORT_REQUESTLIST
          struct pbuf **q = &hs->req;
#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
          struct pbuf **q = inp;
#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
          err = http_post_request(pcb, q, hs, data, data_len, uri, sp2);
          if (err != ERR_OK) {
            /* restore header for next try */
            *sp1 = ' ';
            *sp2 = ' ';
            uri[uri_len] = ' ';
          }
          if (err == ERR_ARG) {
            goto badrequest;
          }
          return err;
        } else
#endif /* LWIP_HTTPD_SUPPORT_POST */
        {
          return http_find_file(hs, uri, is_09);
        }
      } else {
        LWIP_DEBUGF(HTTPD_DEBUG, ("invalid URI\n"));
      }
    }
  }

#if LWIP_HTTPD_SUPPORT_REQUESTLIST
  clen = pbuf_clen(hs->req);
  if ((hs->req->tot_len <= LWIP_HTTPD_REQ_BUFSIZE) &&
    (clen <= LWIP_HTTPD_REQ_QUEUELEN)) {
    /* request not fully received (too short or CRLF is missing) */
    return ERR_INPROGRESS;
  } else
#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
  {
#if LWIP_HTTPD_SUPPORT_POST
badrequest:
#endif /* LWIP_HTTPD_SUPPORT_POST */
    LWIP_DEBUGF(HTTPD_DEBUG, ("bad request\n"));
    /* could not parse request */
    return http_find_error_file(hs, 400);
  }
}

/** Try to find the file specified by uri and, if found, initialize hs
 * accordingly.
 *
 * @param hs the connection state
 * @param uri the HTTP header URI
 * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
 * @return ERR_OK if file was found and hs has been initialized correctly
 *         another err_t otherwise
 */
static err_t
http_find_file(struct http_state *hs, const char *uri, int is_09)
{
  size_t loop;
  struct fs_file *file = NULL;
  char *params;
#if LWIP_HTTPD_CGI
  int i;
  int count;
#endif /* LWIP_HTTPD_CGI */

#if LWIP_HTTPD_SSI
  /*
   * By default, assume we will not be processing server-side-includes
   * tags
   */
  hs->tag_check = false;
#endif /* LWIP_HTTPD_SSI */

  /* Have we been asked for the default root file? */
  if((uri[0] == '/') &&  (uri[1] == 0)) {
    /* Try each of the configured default filenames until we find one
       that exists. */
    for (loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) {
      LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Looking for %s...\n", g_psDefaultFilenames[loop].name));
      file = fs_open((char *)g_psDefaultFilenames[loop].name);
      uri = (char *)g_psDefaultFilenames[loop].name;
      if(file != NULL) {
        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opened.\n"));
#if LWIP_HTTPD_SSI
        hs->tag_check = g_psDefaultFilenames[loop].shtml;
#endif /* LWIP_HTTPD_SSI */
        break;
      }
    }
    if (file == NULL) {
      /* None of the default filenames exist so send back a 404 page */
      file = http_get_404_file(&uri);
#if LWIP_HTTPD_SSI
      hs->tag_check = false;
#endif /* LWIP_HTTPD_SSI */
    }
  } else {
    /* No - we've been asked for a specific file. */
    /* First, isolate the base URI (without any parameters) */
    params = (char *)strchr(uri, '?');
    if (params != NULL) {
      /* URI contains parameters. NULL-terminate the base URI */
      *params = '\0';
      params++;
    }

#if LWIP_HTTPD_CGI
    /* Does the base URI we have isolated correspond to a CGI handler? */
    if (g_iNumCGIs && g_pCGIs) {
      for (i = 0; i < g_iNumCGIs; i++) {
        if (strcmp(uri, g_pCGIs[i].pcCGIName) == 0) {
          /*
           * We found a CGI that handles this URI so extract the
           * parameters and call the handler.
           */
           count = extract_uri_parameters(hs, params);
           uri = g_pCGIs[i].pfnCGIHandler(i, count, hs->params,
                                          hs->param_vals);
           break;
        }
      }
    }
#endif /* LWIP_HTTPD_CGI */

    LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opening %s\n", uri));

    file = fs_open(uri);
    if (file == NULL) {
      file = http_get_404_file(&uri);
    }
#if LWIP_HTTPD_SSI
    if (file != NULL) {
      /*
       * See if we have been asked for an shtml file and, if so,
       * enable tag checking.
       */
      hs->tag_check = false;
      for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
        if (strstr(uri, g_pcSSIExtensions[loop])) {
          hs->tag_check = true;
          break;
        }
      }
    }
#endif /* LWIP_HTTPD_SSI */
  }
  return http_init_file(hs, file, is_09, uri);
}

/** Initialize a http connection with a file to send (if found).
 * Called by http_find_file and http_find_error_file.
 *
 * @param hs http connection state
 * @param file file structure to send (or NULL if not found)
 * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
 * @param uri the HTTP header URI
 * @return ERR_OK if file was found and hs has been initialized correctly
 *         another err_t otherwise
 */
static err_t
http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri)
{
  if (file != NULL) {
    /* file opened, initialise struct http_state */
#if LWIP_HTTPD_SSI
    hs->tag_index = 0;
    hs->tag_state = TAG_NONE;
    hs->parsed = file->data;
    hs->parse_left = file->len;
    hs->tag_end = file->data;
#endif /* LWIP_HTTPD_SSI */
    hs->handle = file;
    hs->file = (char*)file->data;
    LWIP_ASSERT("File length must be positive!", (file->len >= 0));
    hs->left = file->len;
    hs->retries = 0;
#if LWIP_HTTPD_TIMING
    hs->time_started = sys_now();
#endif /* LWIP_HTTPD_TIMING */
#if !LWIP_HTTPD_DYNAMIC_HEADERS
    LWIP_ASSERT("HTTP headers not included in file system", hs->handle->http_header_included);
#endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */
#if LWIP_HTTPD_SUPPORT_V09
    if (hs->handle->http_header_included && is_09) {
      /* HTTP/0.9 responses are sent without HTTP header,
         search for the end of the header. */
      char *file_start = strnstr(hs->file, CRLF CRLF, hs->left);
      if (file_start != NULL) {
        size_t diff = file_start + 4 - hs->file;
        hs->file += diff;
        hs->left -= (u32_t)di

⌨️ 快捷键说明

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