httpd.c

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

C
1,866
字号
    /* Set up to send the first header string. */
    pState->hdr_index = 0;
    pState->hdr_pos = 0;
  }
}
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */

/**
 * Try to send more data on this pcb.
 *
 * @param pcb the pcb to send data
 * @param hs connection state
 */
static u8_t
http_send_data(struct tcp_pcb *pcb, struct http_state *hs)
{
  err_t err;
  u16_t len;
  u16_t mss;
  u8_t data_to_send = false;
#if LWIP_HTTPD_DYNAMIC_HEADERS
  u16_t hdrlen, sendlen;
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */

  LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_send_data: pcb=%p hs=%p left=%d\n", (void*)pcb,
    (void*)hs, hs != NULL ? hs->left : 0));

#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
  if (hs->unrecved_bytes != 0) {
    return 0;
  }
#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */

#if LWIP_HTTPD_DYNAMIC_HEADERS
  /* If we were passed a NULL state structure pointer, ignore the call. */
  if (hs == NULL) {
    return 0;
  }

  /* Assume no error until we find otherwise */
  err = ERR_OK;

  /* Do we have any more header data to send for this file? */
  if(hs->hdr_index < NUM_FILE_HDR_STRINGS) {
    /* How much data can we send? */
    len = tcp_sndbuf(pcb);
    sendlen = len;

    while(len && (hs->hdr_index < NUM_FILE_HDR_STRINGS) && sendlen) {
      const void *ptr;
      u16_t old_sendlen;
      /* How much do we have to send from the current header? */
      hdrlen = (u16_t)strlen(hs->hdrs[hs->hdr_index]);

      /* How much of this can we send? */
      sendlen = (len < (hdrlen - hs->hdr_pos)) ? len : (hdrlen - hs->hdr_pos);

      /* Send this amount of data or as much as we can given memory
      * constraints. */
      ptr = (const void *)(hs->hdrs[hs->hdr_index] + hs->hdr_pos);
      old_sendlen = sendlen;
      err = http_write(pcb, ptr, &sendlen, HTTP_IS_HDR_VOLATILE(hs, ptr));
      if ((err == ERR_OK) && (old_sendlen != sendlen)) {
        /* Remember that we added some more data to be transmitted. */
        data_to_send = true;
      } else if (err != ERR_OK) {
         /* special case: http_write does not try to send 1 byte */
        sendlen = 0;
      }

      /* Fix up the header position for the next time round. */
      hs->hdr_pos += sendlen;
      len -= sendlen;

      /* Have we finished sending this string? */
      if(hs->hdr_pos == hdrlen) {
        /* Yes - move on to the next one */
        hs->hdr_index++;
        hs->hdr_pos = 0;
      }
    }

    /* If we get here and there are still header bytes to send, we send
    * the header information we just wrote immediately.  If there are no
    * more headers to send, but we do have file data to send, drop through
    * to try to send some file data too. */
    if((hs->hdr_index < NUM_FILE_HDR_STRINGS) || !hs->file) {
      LWIP_DEBUGF(HTTPD_DEBUG, ("tcp_output\n"));
      return 1;
    }
  }
#else /* LWIP_HTTPD_DYNAMIC_HEADERS */
  /* Assume no error until we find otherwise */
  err = ERR_OK;
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */

  /* Have we run out of file data to send? If so, we need to read the next
   * block from the file. */
  if (hs->left == 0) {
#if LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS
    int count;
#endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */

    /* Do we have a valid file handle? */
    if (hs->handle == NULL) {
      /* No - close the connection. */
      http_close_conn(pcb, hs);
      return 0;
    }
    if (fs_bytes_left(hs->handle) <= 0) {
      /* We reached the end of the file so this request is done.
       * @todo: don't close here for HTTP/1.1? */
      LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
      http_close_conn(pcb, hs);
      return 0;
    }
#if LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS
    /* Do we already have a send buffer allocated? */
    if(hs->buf) {
      /* Yes - get the length of the buffer */
      count = hs->buf_len;
    } else {
      /* We don't have a send buffer so allocate one up to 2mss bytes long. */
      count = 2 * tcp_mss(pcb);
      do {
        hs->buf = (char*)mem_malloc((mem_size_t)count);
        if (hs->buf != NULL) {
          hs->buf_len = count;
          break;
        }
        count = count / 2;
      } while (count > 100);

      /* Did we get a send buffer? If not, return immediately. */
      if (hs->buf == NULL) {
        LWIP_DEBUGF(HTTPD_DEBUG, ("No buff\n"));
        return 0;
      }
    }

    /* Read a block of data from the file. */
    LWIP_DEBUGF(HTTPD_DEBUG, ("Trying to read %d bytes.\n", count));

    count = fs_read(hs->handle, hs->buf, count);
    if(count < 0) {
      /* We reached the end of the file so this request is done.
       * @todo: don't close here for HTTP/1.1? */
      LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
      http_close_conn(pcb, hs);
      return 1;
    }

    /* Set up to send the block of data we just read */
    LWIP_DEBUGF(HTTPD_DEBUG, ("Read %d bytes.\n", count));
    hs->left = count;
    hs->file = hs->buf;
#if LWIP_HTTPD_SSI
    hs->parse_left = count;
    hs->parsed = hs->buf;
#endif /* LWIP_HTTPD_SSI */
#else /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
    LWIP_ASSERT("SSI and DYNAMIC_HEADERS turned off but eof not reached", 0);
#endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
  }

#if LWIP_HTTPD_SSI
  if(!hs->tag_check) {
#endif /* LWIP_HTTPD_SSI */
    /* We are not processing an SHTML file so no tag checking is necessary.
     * Just send the data as we received it from the file. */

    /* We cannot send more data than space available in the send
       buffer. */
    if (tcp_sndbuf(pcb) < hs->left) {
      len = tcp_sndbuf(pcb);
    } else {
      len = (u16_t)hs->left;
      LWIP_ASSERT("hs->left did not fit into u16_t!", (len == hs->left));
    }
    mss = tcp_mss(pcb);
    if(len > (2 * mss)) {
      len = 2 * mss;
    }

    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;
    }
#if LWIP_HTTPD_SSI
  } else {
    /* We are processing an SHTML file so need to scan for tags and replace
     * them with insert strings. We need to be careful here since a tag may
     * straddle the boundary of two blocks read from the file and we may also
     * have to split the insert string between two tcp_write operations. */

    /* How much data could we send? */
    len = tcp_sndbuf(pcb);

    /* Do we have remaining data to send before parsing more? */
    if(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);
      }
      mss = tcp_mss(pcb);
      if(len > (2 * mss)) {
        len = 2 * mss;
      }

      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;
      }

      /* If the send buffer is full, return now. */
      if(tcp_sndbuf(pcb) == 0) {
        return data_to_send;
      }
    }

    LWIP_DEBUGF(HTTPD_DEBUG, ("State %d, %d left\n", hs->tag_state, hs->parse_left));

    /* We have sent all the data that was already parsed so continue parsing
     * the buffer contents looking for SSI tags. */
    while((hs->parse_left) && (err == ERR_OK)) {
      /* @todo: somewhere in this loop, 'len' should grow again... */
      if (len == 0) {
        return data_to_send;
      }
      switch(hs->tag_state) {
        case TAG_NONE:
          /* We are not currently processing an SSI tag so scan for the
           * start of the lead-in marker. */
          if(*hs->parsed == g_pcTagLeadIn[0]) {
            /* We found what could be the lead-in for a new tag so change
             * state appropriately. */
            hs->tag_state = TAG_LEADIN;
            hs->tag_index = 1;
#if !LWIP_HTTPD_SSI_INCLUDE_TAG
            hs->tag_started = hs->parsed;
#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
          }

          /* Move on to the next character in the buffer */
          hs->parse_left--;
          hs->parsed++;
          break;

        case TAG_LEADIN:
          /* We are processing the lead-in marker, looking for the start of
           * the tag name. */

          /* Have we reached the end of the leadin? */
          if(hs->tag_index == LEN_TAG_LEAD_IN) {
            hs->tag_index = 0;
            hs->tag_state = TAG_FOUND;
          } else {
            /* Have we found the next character we expect for the tag leadin? */
            if(*hs->parsed == g_pcTagLeadIn[hs->tag_index]) {
              /* Yes - move to the next one unless we have found the complete
               * leadin, in which case we start looking for the tag itself */
              hs->tag_index++;
            } else {
              /* We found an unexpected character so this is not a tag. Move
               * back to idle state. */
              hs->tag_state = TAG_NONE;
            }

            /* Move on to the next character in the buffer */
            hs->parse_left--;
            hs->parsed++;
          }
          break;

        case TAG_FOUND:
          /* We are reading the tag name, looking for the start of the
           * lead-out marker and removing any whitespace found. */

          /* Remove leading whitespace between the tag leading and the first
           * tag name character. */
          if((hs->tag_index == 0) && ((*hs->parsed == ' ') ||
             (*hs->parsed == '\t') || (*hs->parsed == '\n') ||
             (*hs->parsed == '\r'))) {
            /* Move on to the next character in the buffer */
            hs->parse_left--;
            hs->parsed++;
            break;
          }

          /* Have we found the end of the tag name? This is signalled by
           * us finding the first leadout character or whitespace */
          if((*hs->parsed == g_pcTagLeadOut[0]) ||
             (*hs->parsed == ' ') || (*hs->parsed == '\t') ||
             (*hs->parsed == '\n')  || (*hs->parsed == '\r')) {

            if(hs->tag_index == 0) {
              /* We read a zero length tag so ignore it. */
              hs->tag_state = TAG_NONE;
            } else {
              /* We read a non-empty tag so go ahead and look for the
               * leadout string. */
              hs->tag_state = TAG_LEADOUT;
              LWIP_ASSERT("hs->tag_index <= 0xff", hs->tag_index <= 0xff);
              hs->tag_name_len = (u8_t)hs->tag_index;
              hs->tag_name[hs->tag_index] = '\0';
              if(*hs->parsed == g_pcTagLeadOut[0]) {
                hs->tag_index = 1;
              } else {
                hs->tag_index = 0;
              }
            }
          } else {
            /* This character is part of the tag name so save it */
            if(hs->tag_index < LWIP_HTTPD_MAX_TAG_NAME_LEN) {
              hs->tag_name[hs->tag_index++] = *hs->parsed;
            } else {
              /* The tag was too long so ignore it. */
              hs->tag_state = TAG_NONE;
            }
          }

          /* Move on to the next character in the buffer */
          hs->parse_left--;
          hs->parsed++;

          break;

        /* We are looking for the end of the lead-out marker. */
        case TAG_LEADOUT:
          /* Remove leading whitespace between the tag leading and the first
           * tag leadout character. */
          if((hs->tag_index == 0) && ((*hs->parsed == ' ') ||
             (*hs->parsed == '\t') || (*hs->parsed == '\n') ||
             (*hs->parsed == '\r'))) {
            /* Move on to the next character in the buffer */
            hs->parse_left--;
            hs->parsed++;
            break;
          }

          /* Have we found the next character we expect for the tag leadout? */
          if(*hs->parsed == g_pcTagLeadOut[hs->tag_index]) {
            /* Yes - move to the next one unless we have found the complete
             * leadout, in which case we need to call the client to process
             * the tag. */

            /* Move on to the next character in the buffer */
            hs->parse_left--;
            hs->parsed++;

            if(hs->tag_index == (LEN_TAG_LEAD_OUT - 1)) {
              /* Call the client to ask for the insert string for the
               * tag we just found. */
#if LWIP_HTTPD_SSI_MULTIPART
              hs->tag_part = 0; /* start with tag part 0 */
#endif /* LWIP_HTTPD_SSI_MULTIPART */
              get_tag_insert(hs);

              /* Next time through, we are going to be sending data
               * immediately, either the end of the block we start
               * sending here or the insert string. */
              hs->tag_index = 0;
              hs->tag_state = TAG_SENDING;
              hs->tag_end = hs->parsed;
#if !LWIP_HTTPD_SSI_INCLUDE_TAG

⌨️ 快捷键说明

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