httpd.c

来自「在luminary平台下移植lwip到freertos,集成开发环境KEIL」· C语言 代码 · 共 1,445 行 · 第 1/3 页

C
1,445
字号
        // Get a pointer to the file extension.  We find this by looking for the
        // last occurrence of "." in the filename passed.
        //
        pszExt = NULL;
        pszWork = strchr(pszURI, '.');
        while(pszWork)
        {
            pszExt = pszWork + 1;
            pszWork = strchr(pszExt, '.');
        }

        //
        // Now determine the content type and add the relevant header for that.
        //
        for(iLoop = 0; (iLoop < NUM_HTTP_HEADERS) && pszExt; iLoop++)
        {
            //
            // Have we found a matching extension?
            //
            if(!strcmp(g_psHTTPHeaders[iLoop].pszExtension, pszExt))
            {
                pState->hdrs[2] =
                  g_psHTTPHeaderStrings[g_psHTTPHeaders[iLoop].ulHeaderIndex];
                break;
            }
        }

        //
        // Reinstate the parameter marker if there was one in the original
        // URI.
        //
        if(pszVars)
        {
            *pszVars = '?';
        }
    }

    //
    // Does the URL passed have any file extension?  If not, we assume it
    // is a special-case URL used for control state notification and we do
    // not send any HTTP headers with the response.
    //
    if(!pszExt)
    {
        //
        // Force the header index to a value indicating that all headers
        // have already been sent.
        //
        pState->hdr_index = NUM_FILE_HDR_STRINGS;
    }
    else
    {
        //
        // Did we find a matching extension?
        //
        if(iLoop == NUM_HTTP_HEADERS)
        {
            //
            // No - use the default, plain text file type.
            //
            pState->hdrs[2] = g_psHTTPHeaderStrings[HTTP_HDR_DEFAULT_TYPE];
        }

        //
        // Set up to send the first header string.
        //
        pState->hdr_index = 0;
        pState->hdr_pos = 0;
    }
}
#endif

/*-----------------------------------------------------------------------------------*/
static void
send_data(struct tcp_pcb *pcb, struct http_state *hs)
{
  err_t err;
  u16_t len;
  u8_t data_to_send = false;
#ifdef DYNAMIC_HTTP_HEADERS
  u16_t hdrlen, sendlen;

  /* 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)
      {
          /* How much do we have to send from the current header? */
          hdrlen = 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. */
          do {
            err = tcp_write(pcb, (const void *)(hs->hdrs[hs->hdr_index] +
                            hs->hdr_pos), sendlen, 0);
            if (err == ERR_MEM) {
              sendlen /= 2;
            }
          } while ((err == ERR_MEM) && (sendlen > 1));

          /* 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 (err == ERR_OK) {
        data_to_send = true;
      }

      /* 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) {
        DEBUG_PRINT("tcp_output\n");
        tcp_output(pcb);
        return;
      }
  }
#else
  /* Assume no error until we find otherwise */
  err = ERR_OK;
#endif

  /* 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)
  {
    int count;

    /* 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 * pcb->mss;
      do {
        hs->buf = mem_malloc(count);
        if(hs->buf) {
          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) {
        DEBUG_PRINT("No buff\n");
        return;
      }
    }

    /* Do we have a valid file handle? */
    if(hs->handle == NULL)
    {
        //
        // No - close the connection.
        //
        close_conn(pcb, hs);
        return;
    }

    /* Read a block of data from the file. */
    DEBUG_PRINT("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 */
      DEBUG_PRINT("End of file.\n");
      fs_close(hs->handle);
      hs->handle = NULL;
      close_conn(pcb, hs);
      return;
    }

    /* Set up to send the block of data we just read */
    DEBUG_PRINT("Read %d bytes.\n", count);
    hs->left = count;
    hs->file = hs->buf;
#ifdef INCLUDE_HTTPD_SSI
    hs->parse_left = count;
    hs->parsed = hs->buf;
#endif
  }

#ifdef INCLUDE_HTTPD_SSI
  if(!hs->tag_check) {
#endif
      /* 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 = hs->left;
        LWIP_ASSERT("hs->left did not fit into u16_t!", (len == hs->left));
      }
      if(len > (2*pcb->mss)) {
        len = 2*pcb->mss;
      }

      do {
        DEBUG_PRINT("Sending %d bytes\n", len);

        /* If the data is being read from a buffer in RAM, we need to copy it
         * into the PCB. If it's in flash, however, we can avoid the copy since
         * the data is obviously not going to be overwritten during the life
         * of the connection.
         */
        err = tcp_write(pcb, hs->file, len,
                        (hs->file < (char *)0x20000000) ? 0 : 1);
        if (err == ERR_MEM) {
          len /= 2;
        }
      } while (err == ERR_MEM && len > 1);

      if (err == ERR_OK) {
        data_to_send = true;
        hs->file += len;
        hs->left -= len;
      }
#ifdef INCLUDE_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 {
          len = (hs->parsed - hs->file);
          LWIP_ASSERT("Data size did not fit into u16_t!",
                      (hs->parsed - hs->file));
        }
        if(len > (2*pcb->mss)) {
          len = 2*pcb->mss;
        }

        do {
          DEBUG_PRINT("Sending %d bytes\n", len);
          err = tcp_write(pcb, hs->file, len, 0);
          if (err == ERR_MEM) {
            len /= 2;
          }
        } while (err == ERR_MEM && len > 1);

        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) {
          if(data_to_send) {
            tcp_output(pcb);
            DEBUG_PRINT("Output\n");
          }
          return;
        }
    }

    DEBUG_PRINT("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)) {
      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;
          }

          /* 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;
              hs->tag_name_len = 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 < 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.
               */
              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 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(len > hs->tag_end - hs->file) {
                    len = hs->tag_end - hs->file;
                }

                do {
                  DEBUG_PRINT("Sending %d bytes\n", len);
                  err = tcp_write(pcb, hs->file, len, 0);
                  if (err == ERR_MEM) {
                    len /= 2;
                  }
                } while (err == ERR_MEM && (len > 1));

                if (err == ERR_OK) {
                  data_to_send = true;
                  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.
               */

⌨️ 快捷键说明

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