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

📄 httpd.c

📁 picoos源码。The RTOS and the TCP/IP stack will be built automatically.
💻 C
📖 第 1 页 / 共 5 页
字号:
        (sysStrnicmp(dec->extension, f, l) == 0))
    {
      conn->contenttype = dec->contenttype;
      break;
    }
    dec++;
  }
}


/*-------------------------------------------------------------------------*/


/* fill the input buffer with upstream data
 */
static sint_t ht_fillInputBuffer(HTTPCONN_t *conn)
{
  int bytes, space;

  if (conn->rxbufptr == conn->rxbuflen)
  {
    conn->rxbufptr = 0;
    conn->rxbuflen = 0;
  }

  if (conn->rxbuflen < HTTP_RXBUFSIZE)
  {
    if (conn->dataavail == 0)
      return -1;  /* can not read from socket */

    conn->lasttransfer = COUNTERVAR;
    conn->dataavail = 0;
    space = HTTP_RXBUFSIZE - (int) conn->rxbuflen;
    bytes = recv(conn->socket, (char*)(conn->rxbuffer + conn->rxbuflen),
                 space, 0);
    if (bytes <= 0)
    {
      ht_destroyConnection(conn);
      return -1;  /* connection closed */
    }

    if (bytes > space)
      return ht_sendStatus(conn, status_500); /* internal server error */

    conn->rxbuflen += (uint_t) bytes;
  }

  return 0;
}


/* read byte from socket. returns with 0 on success.
 */
static sint_t ht_readByte(HTTPCONN_t *conn, u8_t *data)
{
  if (conn->rxbufptr == conn->rxbuflen)
  {
    if (ht_fillInputBuffer(conn) < 0)
      return -1;
  }

  *data = conn->rxbuffer[conn->rxbufptr++];
  return 0;
}


/* Read a full text line from the socket.
 * Returns NULL when line is not yet available.
 */
static char* ht_readLine(HTTPCONN_t *conn)
{
  struct timeval timeout;
  u8_t   b;
  sint_t read = 0;
  fd_set fds;
  int    status;

  for(;;)
  {
    if ((read != 0) && (conn->rxbufptr == conn->rxbuflen))
    {
      FD_ZERO(&fds);
      FD_SET(conn->socket, &fds);
      timeout.tv_sec  = 0;
      timeout.tv_usec = 0;
      status = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
      if (status <= 0)
      {
        if (conn->rxlinelen > 1)
        {
          if ((conn->rxlinebuf[conn->rxlinelen - 2] == 0x0D) &&
              (conn->rxlinebuf[conn->rxlinelen - 1] == 0x0A))
          {
            if ((conn->rxlinelen == 2) && (conn->emptyline == 0))
            {
              conn->rxlinebuf[0] = 0x20;
              conn->rxlinelen++;
            }
            conn->rxlinebuf[conn->rxlinelen - 2] = 0;
            conn->rxlinelen = 0;
            conn->emptyline = 1;
            return conn->rxlinebuf;  /* return full line */
          }
        }
        return NULL; /* no full string yet, and no more data to receive */
      }
      conn->dataavail = 1;
    }

    if (conn->havebackchar != 0)
    {
      conn->havebackchar = 0;
      b = conn->backchar;
    }
    else
    {
      if (ht_readByte(conn, &b) < 0)
        return NULL;  /* no byte available or connection closed */
      read = 1;
    }

    if (b == 0x09)
      b = 0x20;  /* convert tab to space */

    if (b == 0x20) /* space? */
    {
      if (conn->rxlinelen > 1)
      {
        if ((conn->rxlinebuf[conn->rxlinelen - 2] == 0x0D) &&
            (conn->rxlinebuf[conn->rxlinelen - 1] == 0x0A))
        {
          conn->rxlinelen -= 2;
        }
      }
      else
      if (conn->rxlinelen == 0)
      {
        conn->emptyline = 0;
        continue;
      }
    }

    if (conn->rxlinelen > 1)
    {
      if ((conn->rxlinebuf[conn->rxlinelen - 2] == 0x0D) &&
          (conn->rxlinebuf[conn->rxlinelen - 1] == 0x0A))
      {
        conn->backchar = b;
        conn->havebackchar = 1;
        conn->rxlinebuf[conn->rxlinelen - 2] = 0;
        conn->rxlinelen = 0;
        conn->emptyline = 1;
        return conn->rxlinebuf;  /* return full line */
      }
    }

    conn->rxlinebuf[conn->rxlinelen++] = (char) b;

    if (conn->rxlinelen >= (HTTP_MAXSTRLEN-1))
    {
      /* prevent buffer overflow */
      conn->rxlinebuf[conn->rxlinelen] = 0;
      conn->rxlinelen = 0;
      return conn->rxlinebuf;
    }
  }
}


/*-------------------------------------------------------------------------*/


/* This function sends a correctly formatted
 * HTTP status message. In some cases, a small
 * html page is generated to make the status
 * visible for the user.
 */
static sint_t ht_sendStatus(HTTPCONN_t *conn, sint_t status)
{
  char    *buf  = (char*)tempbuf1_g;
  char    *html = (char*)tempbuf2_g;
  sint_t  closeconn = 0;
  sint_t  addhtml = 1;
  u32_t   length = conn->filesize;

  if ((conn->keepalive == 0) ||
      (statustab_g[status].closeconn != 0))
    closeconn = 1;

  if ((conn->method == method_head) ||
      (statustab_g[status].sendhtml == 0))
    addhtml = 0;

  sprintf(buf, "HTTP/1.%i %s\r\n", conn->http11, statustab_g[status].text);

  if (addhtml != 0)
  {
    sysStrcpy(html, "<html><head>\r\n<title>");
    sysStrcat(html, statustab_g[status].text);
    sysStrcat(html, "</title>\r\n</head><body>\r\n<h1>");
#if HTTP_SERVLETS
    if (status == status_busy)
    {
      sysStrcat(html, "The server is busy.");
    }
    else
    if (status == status_idtimeout)
    {
      sysStrcat(html, "The requested session timed out.");
    }
    else
#endif
      sysStrcat(html, statustab_g[status].text);
    sysStrcat(html, "</h1>\r\n");
    if ((status = status_404) && (*conn->filename != 0))
    {
      sysStrcat(html, "<hr><br>\r\n<code><b>File:  ");
      sysStrcat(html, conn->filename);
      sysStrcat(html, "</b></code>\r\n");
    }
#if HTTP_SERVLETS
    else
    if (status == status_busy)
    {
      sysStrcat(html, "<hr><br>\r\n<code><b>Please try later again."
                      "</b></code>\r\n");
    }
#endif
    sysStrcat(html, "</body></html>\r\n");
    length = sysStrlen(html);
  }

#if HTTP_SERVLETS
  if (conn->servlet != NULL)
  {
    sysStrcat(buf, "Cache-Control: no-cache\r\n");
  }
#endif

  if ((status != status_100) && (status != status_101))
  {
    if (closeconn != 0)
    {
      if (conn->http11 != 0)
      {
        sysStrcat(buf, "Connection: close\r\n");
      }
    }
    else
    {
      if (conn->keepalive == KEEPALIVE_UPONREQUEST)
      {
        sysStrcat(buf, "Connection: Keep-Alive\r\n");
      }
    }
  }

  if ((conn->method == method_get) || (conn->method == method_head) ||
      (addhtml != 0))
  {
    if (length != 0)
    {
      sprintf(buf + sysStrlen(buf), "Content-Length: %u\r\n", length);
    }

    if ((status == status_200) &&
        (conn->contenttype != content_unknown))
    {
      sprintf(buf + sysStrlen(buf), "Content-Type: %s\r\n",
              contentTypeStrings_g[conn->contenttype]);
    }
    else
    if (addhtml != 0)
    {
      sysStrcat(buf, "Content-Type: text/html\r\n");
    }
  }

  if (status == status_405)
  {
    sysStrcat(buf, "Allow: GET, HEAD\r\n");
  }

  sysStrcat(buf, "\r\n");

  if (addhtml != 0)
  {
    sysStrcat(buf, html);
  }

  log(conn->socket, "------ reply status ------\r\n");
  log(conn->socket, buf);

  if (send(conn->socket, buf, sysStrlen(buf), 0) <= 0)
  {
    ht_destroyConnection(conn);
    return -1;
  }

  if (statustab_g[status].closeconn != 0)
  {
    ht_destroyConnection(conn);
    return -1;
  }

  conn->lasttransfer = COUNTERVAR;
  return 0;
}


/*-------------------------------------------------------------------------*/


/* small helper: skip the next word in the string
 */
static char* ht_skipWord(char *m)
{
  while ((*m != 0) && (*m != ' ')) m++;
  while (*m == ' ') m++;
  return m;
}


/* small helper: move pointer behind the next colon
 */
static char *ht_movePtrToParam(char *s)
{
  while (*s == ' ') s++;
  if (*s == ':')
  {
    s++;
    while (*s == ' ') s++;
  }
  return s;
}


/* This function reads and decodes the URI
 * that is sent with the HEAD / GET / POST method.
 */
static sint_t ht_readURI(HTTPCONN_t *conn, char *str)
{
  char   *s = str;
  char   *dbuf;
  uint_t b;
  sint_t i, qm;

  i = 0;
  while ((str[i] != 0) && (str[i] != ':')) i++;
  if (str[i] != 0)
  {
    if ((str[i+1] != '/') || (str[i+2] != '/'))
      return ht_sendStatus(conn, status_400); /* bad request */
    s = str + 2;
    while ((*s != 0) && (*s != '/')) s++;
    if (*s == 0)
      return ht_sendStatus(conn, status_400); /* bad request */
  }

  i = 0;
  qm = 0;
  dbuf = conn->filename;
#if HTTP_SERVLETS
  conn->optstring[0] = 0;
  conn->optstring[1] = 0;
#endif
  while ((*s != 0) && (*s != ' '))
  {
    if (*s == '?')
    {
#if HTTP_SERVLETS
      qm = 1;
      dbuf[i] = 0;
      dbuf = conn->optstring;
      s++;
      i = 0;
      continue;
#else
      break;
#endif
    }
    if (*s == '%')
    {
      s++;
      if ((s[0] == 0) || (s[0] == ' ') || 
          (s[1] == 0) || (s[1] == ' ') || 
          (sscanf(s, "%02x", &b) != 1))
        return ht_sendStatus(conn, status_400); /* bad request */

      s++;
      dbuf[i] = (char) b;
    }
    else
    {
      if (qm == 0)
      {
        dbuf[i] = *s;
      }
#if HTTP_SERVLETS
      else
      {
        if (*s == '+')
        {
          dbuf[i] = ' ';
        }
        else
        if (*s == '&')
        {
          dbuf[i] = 0;
        }
        else
        {
          dbuf[i] = *s;
        }
      }
#endif
    }
    if (((qm == 0) && (i >= (HTTP_FNAMESIZE - 1))) ||
        ((qm != 0) && (i >= (HTTP_OPTSTRSIZE - 1))))
    {
      return ht_sendStatus(conn, status_414); /* request URI too large */
    }
    i++;
    s++;
  }
  dbuf[i] = 0;

#if HTTP_SERVLETS
  if (qm != 0)
    dbuf[++i] = 0;
#endif
  
  if (*conn->filename == 0)
    return ht_sendStatus(conn, status_400); /* bad request */

  return 0;
}


/* This function parses the HTTP commands that
 * were sent with a HTTP request from a client.
 */
static sint_t ht_parseCommandLine(HTTPCONN_t *conn, char *cmd)
{
  char *m;
  sint_t i;
  uint_t t1, t2;

  /* first try to get the method */
  if (conn->method == method_none)
  {
    for(i = 0; *(m = methodList_g[i]) != 0; i++)
    {
      if (sysStrncmp(cmd, m, sysStrlen(m)) == 0)
        break;
    }
    conn->method = i;

    if ((conn->method != method_get) && (conn->method != method_head))
      return ht_sendStatus(conn, status_501);  /* method not implemented */

    m = ht_skipWord(cmd);

    /* parse the URI */
    if (ht_readURI(conn, m) != 0)
      return -1;

    m = ht_skipWord(m);

    /* get HTTP version */
    if (sysStrnicmp(m, "HTTP/", 5) == 0)
    {
      if (sscanf(m + 5, "%u.%u", &t1, &t2) == 2)
      {
        if ((t1 >= 1) && (t2 >= 1))
          conn->http11 = 1;  /* is at least HTTP/1.1 */
      }
    }

    if (conn->http11 == 0)
      conn->keepalive = 0;
  }
  else
  if (sysStrnicmp(cmd, "Connection", 10) == 0)
  {
    m = ht_movePtrToParam(cmd + 10);
    if (sysStrnicmp(m, "close", 5) == 0)
    {
      conn->keepalive = 0;
    }
    else
    if (sysStrnicmp(m, "Keep-Alive", 10) == 0)
    {
      conn->keepalive = KEEPALIVE_UPONREQUEST;
    }
  }
  else
  if (sysStrnicmp(cmd, "Content-Length", 14) == 0)
  {
    m = ht_movePtrToParam(cmd + 14);
    if (sscanf(m, "%u", &conn->upStreamLen) != 1)
      return ht_sendStatus(conn, status_400);  /* bad request */

    if (((conn->method == method_get) || (conn->method == method_head)) &&
        (conn->upStreamLen > 0))
      conn->keepalive = 0; /* GET and HEAD do not allow upstream data. */
  }
  else
  if (sysStrnicmp(cmd, "Expect", 6) == 0)
  {
    m = ht_movePtrToParam(cmd + 6);
    if (sysStrnicmp(m, "100-continue", 12) == 0)
    {
      if (conn->http11 != 0)
        conn->cont100 = 1;
    }
    else
    {
      return ht_sendStatus(conn, status_417); /* Expectation Failed */
    }
  }

  return 0;
}


/* initialize next transfer
 */
static void ht_nextTransfer(HTTPCONN_t *conn)
{
  if (conn->socket >= 0)
  {
    ht_closeFile(conn);

    if ((conn->keepalive == 0) ||

⌨️ 快捷键说明

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