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

📄 http.c

📁 一个WEB服务器的性能测试工具
💻 C
字号:
/*    httperf -- a tool for measuring web server performance    Copyright (C) 2000  Hewlett-Packard Company    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>    This file is part of httperf, a web server performance measurment    tool.    This program is free software; you can redistribute it and/or    modify it under the terms of the GNU General Public License as    published by the Free Software Foundation; either version 2 of the    License, or (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA    02111-1307 USA*/#include <assert.h>#include <ctype.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <httperf.h>#include <http.h>#include <call.h>#include <event.h>#include <conn.h>/* Read a CRLF terminated line of characters into c->reply.line.   Returns 1 when the line is complete, 0 when the line is incomplete   and more data is needed.  */static intget_line (Call *c, char **bufp, size_t *buf_lenp){  size_t to_copy, buf_len = *buf_lenp;  Conn *s = c->conn;  char *buf = *bufp;  const char *eol;  int has_lf;  if (buf_len <= 0)    return 0;  /* Note that core.c guarantees that BUF is '\0' terminated. */  eol = strchr (buf, '\n');  if (eol)    ++eol;  else    eol = buf + buf_len;  to_copy = eol - buf;  buf_len -= to_copy;  if (s->line.iov_len + to_copy >= sizeof (s->line_buf))    {      fprintf (stderr,	       "%s.get_line: truncating header from %lu to %lu bytes\n",	       prog_name, (u_long) (s->line.iov_len + to_copy),	       (u_long) sizeof (s->line_buf));      to_copy = sizeof (s->line_buf) - 1 - s->line.iov_len;    }  memcpy ((char *) s->line.iov_base + s->line.iov_len, buf, to_copy);  s->line.iov_len += to_copy;  has_lf = ((char *) s->line.iov_base)[s->line.iov_len - 1] == '\n';  *bufp = (char *) eol;  *buf_lenp = buf_len;  if (has_lf || s->line.iov_len == sizeof (s->line_buf) - 1)    {      /* We got a full header line.  Chop off \r\n at the tail if	 necessary.  */      if (((char *) s->line.iov_base)[s->line.iov_len - 1] == '\n')	{	  --s->line.iov_len;	  if (((char *) s->line.iov_base)[s->line.iov_len - 1] == '\r')	    --s->line.iov_len;	}      ((char *) s->line.iov_base)[s->line.iov_len] = '\0';      return 1;    }  return 0;}static voidparse_status_line (Call *c, char **bufp, size_t *buf_lenp){  char *buf, *buf_start = *bufp;  u_int major, minor, status;  Conn *s = c->conn;  Any_Type arg;  s->is_chunked = 0;  /* default to "infinite" content length: */  s->content_length = ~(size_t) 0;  if (!get_line (c, bufp, buf_lenp))    return;  buf = c->conn->line.iov_base;  if (sscanf (buf, "HTTP/%u.%u %u ", &major, &minor, &status) == 3)    {      c->reply.version = 0x10000*major + minor;      c->reply.status = status;    }  else    {      c->reply.version = 0x10000;		/* default to 1.0 */      c->reply.status = 599;      if (c->reply.status == 599)	fprintf (stderr, "%s.parse_status_line: invalid status line `%s'!!\n",		 prog_name, buf);    }  if (DBG > 0)    fprintf (stderr,	     "parse_status_line.%lu: reply is HTTP/%u.%u, status = %d\n",	     c->id, c->reply.version / 0x10000, c->reply.version & 0xffff,	     c->reply.status);  /* Determine whether we should be expecting a message body.  HEAD     never includes an entity.  For other methods, things depend on     the status code.  */  if (strcmp ((char *) c->req.iov[IE_METHOD].iov_base, "HEAD") == 0)    s->has_body = 0;  else    {      s->has_body = 1;      switch (status / 100)	{	case 1: /* informational */	  s->has_body = 0;	  if (status == 100)	    {	      arg.l = c->reply.status;	      event_signal (EV_CALL_RECV_START, (Object *) c, arg);	      s->state = S_REPLY_CONTINUE;	      goto done;	    }	  break;	case 2: /* success */	case 3: /* redirection */	  switch (status)	    {	    case 204: /* No Content */	    case 205: /* Reset Content */	    case 304: /* Not Modified */	      s->has_body = 0;	      break;	    }	  break;	case 4: /* client errors */	case 5: /* server errors */	  break;	default:	  fprintf (stderr, "%s.parse_status_line: bad status %u\n",		   prog_name, status);	  break;	}    }  arg.l = c->reply.status;  event_signal (EV_CALL_RECV_START, (Object *) c, arg);  if (s->state >= S_CLOSING)    return;  s->state = S_REPLY_HEADER; done:  c->reply.header_bytes += *bufp - buf_start;  s->line.iov_len = 0;		}static voidparse_headers (Call *c, char **bufp, size_t *buf_lenp){  char *hdr, *buf_start = *bufp;  Conn *s = c->conn;  size_t hdr_len;  Any_Type arg;  while (get_line (c, bufp, buf_lenp) > 0)    {      hdr = s->line.iov_base;      hdr_len = s->line.iov_len;      if (!hdr_len)	{	  /* empty header implies end of headers */	  if (s->has_body)	    if (s->is_chunked)	      {		s->content_length = 0;		s->state = S_REPLY_CHUNKED;	      }	    else	      s->state = S_REPLY_DATA;	  else if (s->state == S_REPLY_CONTINUE)	    s->state = S_REPLY_HEADER;	  else	    s->state = S_REPLY_DONE;	  break;	}      /* process line as a regular header: */      switch (tolower (*hdr))	{	case 'c':	  if (strncasecmp (hdr, "content-length:", 15) == 0)	    {	      hdr += 15;	      s->content_length = strtoul (hdr, 0, 10);	    }	  break;	case 't':	  if (strncasecmp (hdr, "transfer-encoding:", 18) == 0)	    {	      hdr += 18;	      while (isspace (*hdr))		++hdr;	      if (strcasecmp (hdr, "chunked") == 0)		s->is_chunked = 1;	      else		fprintf (stderr, "%s.parse_headers: unknown transfer "			 "encoding `%s'\n", prog_name, hdr);	    }	  break;	}      arg.vp = &s->line;      event_signal (EV_CALL_RECV_HDR, (Object *) c, arg);      if (s->state >= S_CLOSING)	return;      s->line.iov_len = 0;		    }  c->reply.header_bytes += *bufp - buf_start;}static voidparse_footers (Call *c, char **bufp, size_t *buf_lenp){  char *hdr, *buf_start = *bufp;  Conn *s = c->conn;  size_t hdr_len;  Any_Type arg;  while (get_line (c, bufp, buf_lenp) > 0)    {      hdr = s->line.iov_base;      hdr_len = s->line.iov_len;      if (!hdr_len)	{	  /* empty footer implies end of footers */	  s->state = S_REPLY_DONE;	  break;	}      /* process line as a regular footer: */      arg.vp = &s->line;      event_signal (EV_CALL_RECV_FOOTER, (Object *) c, arg);      if (s->state >= S_CLOSING)	return;      s->line.iov_len = 0;		    }  c->reply.footer_bytes += *bufp - buf_start;}static intparse_data (Call *c, char **bufp, size_t *buf_lenp){  size_t bytes_needed, buf_len = *buf_lenp;  Conn *s = c->conn;  char *buf = *bufp;  struct iovec iov;  Any_Type arg;  bytes_needed = (s->content_length - c->reply.content_bytes);  if (buf_len > bytes_needed)    buf_len = bytes_needed;  iov.iov_base = (caddr_t) buf;  iov.iov_len = buf_len;  arg.vp = &iov;  event_signal (EV_CALL_RECV_DATA, (Object *) c, arg);  c->reply.content_bytes += buf_len;  *bufp = buf + buf_len;  *buf_lenp -= buf_len;  return (buf_len == bytes_needed);}static voidxfer_chunked  (Call *c, char **bufp, size_t *buf_lenp){  Conn *s = c->conn;  size_t chunk_length;  char *end;  while (*buf_lenp > 0 && s->state < S_CLOSING)    {      if (c->reply.content_bytes >= s->content_length)	{	  /* need to parse next chunk length line: */	  if (!get_line (c, bufp, buf_lenp))	    return;				/* need more data */	  if (s->line.iov_len == 0)	    continue;				/* skip over empty line */	  errno = 0;	  chunk_length = strtoul (s->line.iov_base, &end, 16);	  s->line.iov_len = 0;	  if (errno == ERANGE || end == s->line.iov_base)	    {	      fprintf (stderr, "%s.xfer_chunked: bad chunk line `%s'\n",		       prog_name, (char *) s->line.iov_base);	      continue;	    }	  if (chunk_length == 0)	    {	      /* a final chunk of zero bytes indicates the end of the reply */	      s->state = S_REPLY_FOOTER;	      return;	    }	  s->content_length += chunk_length;	}      parse_data (c, bufp, buf_lenp);    }}voidhttp_process_reply_bytes (Call *c, char **bufp, size_t *buf_lenp){  Conn *s = c->conn;  struct iovec iov;  Any_Type arg;  iov.iov_base = *bufp;  iov.iov_len = *buf_lenp;  arg.vp = &iov;  event_signal (EV_CALL_RECV_RAW_DATA, (Object *) c, arg);  do    {      switch (s->state)	{	case S_REPLY_STATUS:	  parse_status_line (c, bufp, buf_lenp);	  break;	case S_REPLY_HEADER:	  parse_headers (c, bufp, buf_lenp);	  break;	case S_REPLY_FOOTER:	  parse_footers (c, bufp, buf_lenp);	  break;	case S_REPLY_DATA:	  if (parse_data (c, bufp, buf_lenp) && s->state < S_CLOSING)	    s->state = S_REPLY_DONE;	  break;	case S_REPLY_CONTINUE:	  parse_headers (c, bufp, buf_lenp);	  break;	case S_REPLY_CHUNKED:	  xfer_chunked (c, bufp, buf_lenp);	  break;	case S_REPLY_DONE:	  return;	default:	  fprintf (stderr, "%s.http_process_reply_bytes: bad state %d\n",		   prog_name, s->state);	  exit (1);	}    }  while (*buf_lenp > 0 && s->state < S_CLOSING);}

⌨️ 快捷键说明

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