httpd.c

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

C
1,866
字号
              hs->parsed = hs->tag_started;
#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/

              /* If there is any unsent data in the buffer prior to the
               * tag, we need to send it now. */
              if (hs->tag_end > hs->file) {
                /* How much of the data can we send? */
#if LWIP_HTTPD_SSI_INCLUDE_TAG
                if(len > hs->tag_end - hs->file) {
                  len = (u16_t)(hs->tag_end - hs->file);
                }
#else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
                if(len > hs->tag_started - hs->file) {
                  /* we would include the tag in sending */
                  len = (u16_t)(hs->tag_started - hs->file);
                }
#endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/

                err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
                if (err == ERR_OK) {
                  data_to_send = true;
#if !LWIP_HTTPD_SSI_INCLUDE_TAG
                  if(hs->tag_started <= hs->file) {
                    /* pretend to have sent the tag, too */
                    len += hs->tag_end - hs->tag_started;
                  }
#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
                  hs->file += len;
                  hs->left -= len;
                }
              }
            } else {
              hs->tag_index++;
            }
          } else {
            /* We found an unexpected character so this is not a tag. Move
             * back to idle state. */
            hs->parse_left--;
            hs->parsed++;
            hs->tag_state = TAG_NONE;
          }
          break;

        /*
         * We have found a valid tag and are in the process of sending
         * data as a result of that discovery. We send either remaining data
         * from the file prior to the insert point or the insert string itself.
         */
        case TAG_SENDING:
          /* Do we have any remaining file data to send from the buffer prior
           * to the tag? */
          if(hs->tag_end > hs->file) {
            /* How much of the data can we send? */
#if LWIP_HTTPD_SSI_INCLUDE_TAG
            if(len > hs->tag_end - hs->file) {
              len = (u16_t)(hs->tag_end - hs->file);
            }
#else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
            LWIP_ASSERT("hs->started >= hs->file", hs->tag_started >= hs->file);
            if (len > hs->tag_started - hs->file) {
              /* we would include the tag in sending */
              len = (u16_t)(hs->tag_started - hs->file);
            }
#endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
            if (len != 0) {
              err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
            } else {
              err = ERR_OK;
            }
            if (err == ERR_OK) {
              data_to_send = true;
#if !LWIP_HTTPD_SSI_INCLUDE_TAG
              if(hs->tag_started <= hs->file) {
                /* pretend to have sent the tag, too */
                len += hs->tag_end - hs->tag_started;
              }
#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
              hs->file += len;
              hs->left -= len;
            }
          } else {
#if LWIP_HTTPD_SSI_MULTIPART
            if(hs->tag_index >= hs->tag_insert_len) {
              /* Did the last SSIHandler have more to send? */
              if (hs->tag_part != HTTPD_LAST_TAG_PART) {
                /* If so, call it again */
                hs->tag_index = 0;
                get_tag_insert(hs);
              }
            }
#endif /* LWIP_HTTPD_SSI_MULTIPART */

            /* Do we still have insert data left to send? */
            if(hs->tag_index < hs->tag_insert_len) {
              /* We are sending the insert string itself. How much of the
               * insert can we send? */
              if(len > (hs->tag_insert_len - hs->tag_index)) {
                len = (hs->tag_insert_len - hs->tag_index);
              }

              /* Note that we set the copy flag here since we only have a
               * single tag insert buffer per connection. If we don't do
               * this, insert corruption can occur if more than one insert
               * is processed before we call tcp_output. */
              err = http_write(pcb, &(hs->tag_insert[hs->tag_index]), &len,
                               HTTP_IS_TAG_VOLATILE(hs));
              if (err == ERR_OK) {
                data_to_send = true;
                hs->tag_index += len;
                /* Don't return here: keep on sending data */
              }
            } else {
              /* We have sent all the insert data so go back to looking for
               * a new tag. */
              LWIP_DEBUGF(HTTPD_DEBUG, ("Everything sent.\n"));
              hs->tag_index = 0;
              hs->tag_state = TAG_NONE;
#if !LWIP_HTTPD_SSI_INCLUDE_TAG
              hs->parsed = hs->tag_end;
#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
            }
            break;
        }
      }
    }

    /* If we drop out of the end of the for loop, this implies we must have
     * file data to send so send it now. In TAG_SENDING state, we've already
     * handled this so skip the send if that's the case. */
    if((hs->tag_state != TAG_SENDING) && (hs->parsed > hs->file)) {
      /* We cannot send more data than space available in the send
         buffer. */
      if (tcp_sndbuf(pcb) < (hs->parsed - hs->file)) {
        len = tcp_sndbuf(pcb);
      } else {
        LWIP_ASSERT("Data size does not fit into u16_t!",
                    (hs->parsed - hs->file) <= 0xffff);
        len = (u16_t)(hs->parsed - hs->file);
      }
      if(len > (2 * tcp_mss(pcb))) {
        len = 2 * tcp_mss(pcb);
      }

      err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
      if (err == ERR_OK) {
        data_to_send = true;
        hs->file += len;
        hs->left -= len;
      }
    }
  }
#endif /* LWIP_HTTPD_SSI */

  if((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0)) {
    /* We reached the end of the file so this request is done.
     * This adds the FIN flag right into the last data segment.
     * @todo: don't close here for HTTP/1.1? */
    LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
    http_close_conn(pcb, hs);
    return 0;
  }
  LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("send_data end.\n"));
  return data_to_send;
}

#if LWIP_HTTPD_SUPPORT_EXTSTATUS
/** Initialize a http connection with a file to send for an error message
 *
 * @param hs http connection state
 * @param error_nr HTTP error number
 * @return ERR_OK if file was found and hs has been initialized correctly
 *         another err_t otherwise
 */
static err_t
http_find_error_file(struct http_state *hs, u16_t error_nr)
{
  const char *uri1, *uri2, *uri3;
  struct fs_file *file;

  if (error_nr == 501) {
    uri1 = "/501.html";
    uri2 = "/501.htm";
    uri3 = "/501.shtml";
  } else {
    /* 400 (bad request is the default) */
    uri1 = "/400.html";
    uri2 = "/400.htm";
    uri3 = "/400.shtml";
  }
  file = fs_open(uri1);
  if (file == NULL) {
    file = fs_open(uri2);
    if (file == NULL) {
      file = fs_open(uri3);
      if (file == NULL) {
        LWIP_DEBUGF(HTTPD_DEBUG, ("Error page for error %"U16_F" not found\n",
          error_nr));
        return ERR_ARG;
      }
    }
  }
  return http_init_file(hs, file, 0, NULL);
}
#else /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
#define http_find_error_file(hs, error_nr) ERR_ARG
#endif /* LWIP_HTTPD_SUPPORT_EXTSTATUS */

/**
 * Get the file struct for a 404 error page.
 * Tries some file names and returns NULL if none found.
 *
 * @param uri pointer that receives the actual file name URI
 * @return file struct for the error page or NULL no matching file was found
 */
static struct fs_file *
http_get_404_file(const char **uri)
{
  struct fs_file *file;

  *uri = "/404.html";
  file = fs_open(*uri);
  if(file == NULL) {
    /* 404.html doesn't exist. Try 404.htm instead. */
    *uri = "/404.htm";
    file = fs_open(*uri);
    if(file == NULL) {
      /* 404.htm doesn't exist either. Try 404.shtml instead. */
      *uri = "/404.shtml";
      file = fs_open(*uri);
      if(file == NULL) {
        /* 404.htm doesn't exist either. Indicate to the caller that it should
         * send back a default 404 page.
         */
        *uri = NULL;
      }
    }
  }

  return file;
}

#if LWIP_HTTPD_SUPPORT_POST
static err_t
http_handle_post_finished(struct http_state *hs)
{
  /* application error or POST finished */
  /* NULL-terminate the buffer */
  http_post_response_filename[0] = 0;
  httpd_post_finished(hs, http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN);
  return http_find_file(hs, http_post_response_filename, 0);
}

/** Pass received POST body data to the application and correctly handle
 * returning a response document or closing the connection.
 * ATTENTION: The application is responsible for the pbuf now, so don't free it!
 *
 * @param hs http connection state
 * @param p pbuf to pass to the application
 * @return ERR_OK if passed successfully, another err_t if the response file
 *         hasn't been found (after POST finished)
 */
static err_t
http_post_rxpbuf(struct http_state *hs, struct pbuf *p)
{
  err_t err;

  /* adjust remaining Content-Length */
  if (hs->post_content_len_left < p->tot_len) {
    hs->post_content_len_left = 0;
  } else {
    hs->post_content_len_left -= p->tot_len;
  }
  err = httpd_post_receive_data(hs, p);
  if ((err != ERR_OK) || (hs->post_content_len_left == 0)) {
#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
    if (hs->unrecved_bytes != 0) {
       return ERR_OK;
    }
#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
    /* application error or POST finished */
    return http_handle_post_finished(hs);
  }

  return ERR_OK;
}

/** Handle a post request. Called from http_parse_request when method 'POST'
 * is found.
 *
 * @param pcb The tcp_pcb which received this packet.
 * @param p The input pbuf (containing the POST header and body).
 * @param hs The http connection state.
 * @param data HTTP request (header and part of body) from input pbuf(s).
 * @param data_len Size of 'data'.
 * @param uri The HTTP URI parsed from input pbuf(s).
 * @param uri_end Pointer to the end of 'uri' (here, the rest of the HTTP
 *                header starts).
 * @return ERR_OK: POST correctly parsed and accepted by the application.
 *         ERR_INPROGRESS: POST not completely parsed (no error yet)
 *         another err_t: Error parsing POST or denied by the application
 */
static err_t
http_post_request(struct tcp_pcb *pcb, struct pbuf **inp, struct http_state *hs,
                  char *data, u16_t data_len, char *uri, char *uri_end)
{
  err_t err;
  /* search for end-of-header (first double-CRLF) */
  char* crlfcrlf = strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data));

#if LWIP_HTTPD_POST_MANUAL_WND
  hs->pcb = pcb;
#else /* LWIP_HTTPD_POST_MANUAL_WND */
  LWIP_UNUSED_ARG(pcb); /* only used for LWIP_HTTPD_POST_MANUAL_WND */
#endif /*  LWIP_HTTPD_POST_MANUAL_WND */

  if (crlfcrlf != NULL) {
    /* search for "Content-Length: " */
#define HTTP_HDR_CONTENT_LEN                "Content-Length: "
#define HTTP_HDR_CONTENT_LEN_LEN            16
#define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN  10
    char *scontent_len = strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1));
    if (scontent_len != NULL) {
      char *scontent_len_end = strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN);
      if (scontent_len_end != NULL) {
        int content_len;
        char *conten_len_num = scontent_len + HTTP_HDR_CONTENT_LEN_LEN;
        *scontent_len_end = 0;
        content_len = atoi(conten_len_num);
        if (content_len > 0) {
          /* adjust length of HTTP header passed to application */
          const char *hdr_start_after_uri = uri_end + 1;
          u16_t hdr_len = LWIP_MIN(data_len, crlfcrlf + 4 - data);
          u16_t hdr_data_len = LWIP_MIN(data_len, crlfcrlf + 4 - hdr_start_after_uri);
          u8_t post_auto_wnd = 1;
          http_post_response_filename[0] = 0;
          err = httpd_post_begin(hs, uri, hdr_start_after_uri, hdr_data_len, content_len,
            http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN, &post_auto_wnd);
          if (err == ERR_OK) {
            /* try to pass in data of the first pbuf(s) */
            struct pbuf *q = *inp;
            u16_t start_offset = hdr_len;
#if LWIP_HTTPD_POST_MANUAL_WND
            hs->no_auto_wnd = !post_auto_wnd;
#endif /* LWIP_HTTPD_POST_MANUAL_WND */
            /* set the Content-Length to be received for this POST */
            hs->post_content_len_left = (u32_t)content_len;

            /* get to the pbuf where the body starts */
            while((q != NULL) && (q->len <= start_offset)) {
              struct pbuf *head = q;
              start_offset -= q->len;
              q = q->next;
              /* free the head pbuf */
              head->next = NULL;
              pbuf_free(head);
            }
            *inp = NULL;
            if (q != NULL) {
              /* hide the remaining HTTP header */
              pbuf_header(q, -(s16_t)start_offset);
#if LWIP_HTTPD_POST_MANUAL_WND
              if (!post_auto_wnd) {
                /* already tcp_recved() this data... */
                hs->unrecved_bytes = q->tot_len;
              }
#endif /* LWIP_HTTPD_POST_MANUAL_WND */
              return http_post_rxpbuf(hs, q);
            } else {
              return ERR_OK;
            }
          } else {
            /* return file passed from application */
            return http_find_file(hs, http_post_response_filename, 0);
          }

⌨️ 快捷键说明

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