Ejemplo n.º 1
0
static ngx_int_t
process_status_line(ngx_http_request_t *r)
{
    ngx_int_t             rc;
    ngx_http_upstream_t  *u;
    passenger_context_t  *context;

    context = ngx_http_get_module_ctx(r, ngx_http_passenger_module);

    if (context == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    rc = parse_status_line(r, context);

    if (rc == NGX_AGAIN) {
        return rc;
    }

    u = r->upstream;

    if (rc == NGX_HTTP_SCGI_PARSE_NO_HEADER) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "upstream sent no valid HTTP/1.0 header");

#if 0
        if (u->accel) {
            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
        }
#endif

        r->http_version = NGX_HTTP_VERSION_9;
        u->headers_in.status_n = NGX_HTTP_OK;
        u->state->status = NGX_HTTP_OK;

        return NGX_OK;
    }

    u->headers_in.status_n = context->status;
    u->state->status = context->status;

    u->headers_in.status_line.len = context->status_end - context->status_start;
    u->headers_in.status_line.data = ngx_palloc(r->pool,
                                                u->headers_in.status_line.len);
    if (u->headers_in.status_line.data == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_memcpy(u->headers_in.status_line.data, context->status_start,
               u->headers_in.status_line.len);

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http scgi status %ui \"%V\"",
                   u->headers_in.status_n, &u->headers_in.status_line);

    u->process_header = process_header;

    return process_header(r);
}
Ejemplo n.º 2
0
void
http_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);
}
Ejemplo n.º 3
0
bool proxy_connection::read_status_line(unsigned fd, size_t& total)
{
	io_result res;

	do {
		if ((res = read(fd, _M_client->_M_body, total)) == IO_ERROR) {
			_M_client->_M_error = http_error::GATEWAY_TIMEOUT;

			return false;
		} else if (res == IO_NO_DATA_READ) {
			return true;
		}

		_M_client->_M_timestamp = now::_M_time;

		parse_result parse_result = parse_status_line(fd);
		if (parse_result == PARSE_ERROR) {
			_M_client->_M_error = http_error::BAD_GATEWAY;

			return false;
		} else if (parse_result == PARSING_COMPLETED) {
			// Reuse client's headers.
			_M_client->_M_headers.reset();

			parse_result = parse_headers(fd);
			if (parse_result == PARSE_ERROR) {
				_M_client->_M_error = http_error::BAD_GATEWAY;

				return false;
			} else if (parse_result == PARSING_NOT_COMPLETED) {
				_M_state = READING_HEADERS_STATE;
			} else {
				_M_state = PROCESSING_RESPONSE_STATE;
			}

			return true;
		}
	} while (res == IO_SUCCESS);

	return true;
}
Ejemplo n.º 4
0
struct status_line *
ini_load_status_line(const char *inifile)
{
	static const char * const system = SYSCONFDIR "/i3blocks.conf";
	const char * const home = getenv("HOME");
	char buf[PATH_MAX];
	FILE *fp;
	struct status_line *status;

	struct status_line *parse(void) {
		status = calloc(1, sizeof(struct status_line));
		if (status && parse_status_line(fp, status)) {
			free(status->blocks);
			free(status->updated_blocks);
			free(status);
			status = NULL;
		}

		if (fclose(fp))
			errorx("fclose");

		return status;
	}
Ejemplo n.º 5
0
utility_retcode_t rtsp_parse_response(struct rtsp_response *response)
{
	utility_retcode_t ret;
	FUNC_ENTER;

	ret = parse_status_line(response);
	if (UTILITY_SUCCESS != ret) {
		ERRR("Failed to parse status line\n");
		goto out;
	}

	ret = get_header_list(response);
	if (UTILITY_SUCCESS != ret) {
		ERRR("Failed to parse headers\n");
		goto out;
	}

	/* Here we will need to parse the message body, if any. */

out:
	FUNC_RETURN;
	return ret;
}
Ejemplo n.º 6
0
static svn_error_t *
multistatus_closed(svn_ra_serf__xml_estate_t *xes,
                   void *baton,
                   int leaving_state,
                   const svn_string_t *cdata,
                   apr_hash_t *attrs,
                   apr_pool_t *scratch_pool)
{
  struct svn_ra_serf__server_error_t *server_error = baton;
  const char *errcode;
  const char *status;

  switch (leaving_state)
    {
      case MS_RESPONSE_HREF:
        {
          apr_status_t result;
          apr_uri_t uri;

          result = apr_uri_parse(scratch_pool, cdata->data, &uri);
          if (result)
            return svn_ra_serf__wrap_err(result, NULL);
          svn_ra_serf__xml_note(xes, MS_RESPONSE, "path",
                                svn_urlpath__canonicalize(uri.path, scratch_pool));
        }
        break;
      case MS_RESPONSE_STATUS:
        svn_ra_serf__xml_note(xes, MS_RESPONSE, "status", cdata->data);
        break;
      case MS_RESPONSE_ERROR_HUMANREADABLE:
        svn_ra_serf__xml_note(xes, MS_RESPONSE, "human-readable", cdata->data);
        errcode = svn_hash_gets(attrs, "errcode");
        if (errcode)
          svn_ra_serf__xml_note(xes, MS_RESPONSE, "errcode", errcode);
        break;
      case MS_RESPONSE:
        if ((status = svn_hash__get_cstring(attrs, "status", NULL)) != NULL)
          {
            error_item_t *item;

            item = apr_pcalloc(server_error->pool, sizeof(*item));

            item->path = apr_pstrdup(server_error->pool,
                                     svn_hash_gets(attrs, "path"));

            SVN_ERR(parse_status_line(&item->http_status,
                                      &item->http_reason,
                                      status,
                                      server_error->pool,
                                      scratch_pool));

            /* Do we have a mod_dav specific message? */
            item->message = svn_hash_gets(attrs, "human-readable");

            if (item->message)
              {
                if ((errcode = svn_hash_gets(attrs, "errcode")) != NULL)
                  {
                    apr_int64_t val;

                    SVN_ERR(svn_cstring_atoi64(&val, errcode));
                    item->apr_err = (apr_status_t)val;
                  }

                item->message = apr_pstrdup(server_error->pool, item->message);
              }
            else
              item->message = apr_pstrdup(server_error->pool,
                                          svn_hash_gets(attrs, "description"));

            APR_ARRAY_PUSH(server_error->items, error_item_t *) = item;
          }
        break;


      case MS_PROPSTAT_STATUS:
        svn_ra_serf__xml_note(xes, MS_PROPSTAT, "status", cdata->data);
        break;
      case MS_PROPSTAT_ERROR_HUMANREADABLE:
        svn_ra_serf__xml_note(xes, MS_PROPSTAT, "human-readable", cdata->data);
        errcode = svn_hash_gets(attrs, "errcode");
        if (errcode)
          svn_ra_serf__xml_note(xes, MS_PROPSTAT, "errcode", errcode);
        break;
      case MS_PROPSTAT_RESPONSEDESCRIPTION:
        svn_ra_serf__xml_note(xes, MS_PROPSTAT, "description",
                              cdata->data);
        break;

      case MS_PROPSTAT:
        if ((status = svn_hash__get_cstring(attrs, "status", NULL)) != NULL)
          {
            apr_hash_t *response_attrs;
            error_item_t *item;

            response_attrs = svn_ra_serf__xml_gather_since(xes, MS_RESPONSE);
            item = apr_pcalloc(server_error->pool, sizeof(*item));

            item->path = apr_pstrdup(server_error->pool,
                                     svn_hash_gets(response_attrs, "path"));
            item->propname = apr_pstrdup(server_error->pool,
                                         svn_hash_gets(attrs, "propname"));

            SVN_ERR(parse_status_line(&item->http_status,
                                      &item->http_reason,
                                      status,
                                      server_error->pool,
                                      scratch_pool));

            /* Do we have a mod_dav specific message? */
            item->message = svn_hash_gets(attrs, "human-readable");

            if (item->message)
              {
                if ((errcode = svn_hash_gets(attrs, "errcode")) != NULL)
                  {
                    apr_int64_t val;

                    SVN_ERR(svn_cstring_atoi64(&val, errcode));
                    item->apr_err = (apr_status_t)val;
                  }

                item->message = apr_pstrdup(server_error->pool, item->message);
              }
            else
              item->message = apr_pstrdup(server_error->pool,
                                          svn_hash_gets(attrs, "description"));


            APR_ARRAY_PUSH(server_error->items, error_item_t *) = item;
          }
Ejemplo n.º 7
0
static int
read_reply(int s, cachemgr_request * req)
{
    char buf[4 * 1024];
    FILE *fp = fdopen(s, "r");
    /* interpretation states */
    enum {
	isStatusLine, isHeaders, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError
    } istate = isStatusLine;
    int parse_menu = 0;
    const char *action = req->action;
    const char *statusStr = NULL;
    int status = -1;
    if (0 == strlen(req->action))
	parse_menu = 1;
    else if (0 == strcasecmp(req->action, "menu"))
	parse_menu = 1;
    if (fp == NULL) {
	perror("fdopen");
	return 1;
    }
    if (parse_menu)
	action = "menu";
    /* read reply interpreting one line at a time depending on state */
    while (istate < isEof) {
	if (!fgets(buf, sizeof(buf), fp))
	    istate = istate == isForward ? isForwardEof : isEof;
	switch (istate) {
	case isStatusLine:
	    /* get HTTP status */
	    /* uncomment the following if you want to debug headers */
	    /* fputs("\r\n\r\n", stdout); */
	    status = parse_status_line(buf, &statusStr);
	    istate = status == 200 ? isHeaders : isForward;
	    /* if cache asks for authentication, we have to reset our info */
	    if (status == 401 || status == 407) {
		reset_auth(req);
		status = 403;	/* Forbiden, see comments in case isForward: */
	    }
	    /* this is a way to pass HTTP status to the Web server */
	    if (statusStr)
		printf("Status: %d %s", status, statusStr);	/* statusStr has '\n' */
	    break;
	case isHeaders:
	    /* forward header field */
	    if (!strcmp(buf, "\r\n")) {		/* end of headers */
		fputs("Content-Type: text/html\r\n", stdout);	/* add our type */
		istate = isBodyStart;
	    }
	    if (strncasecmp(buf, "Content-Type:", 13))	/* filter out their type */
		fputs(buf, stdout);
	    break;
	case isBodyStart:
	    printf("<HTML><HEAD><TITLE>CacheMgr@%s: %s</TITLE></HEAD><BODY>\n",
		req->hostname, action);
	    if (parse_menu) {
		printf("<H2><a href=\"%s\">Cache Manager</a> menu for %s:</H2>",
		    menu_url(req, "authenticate"), req->hostname);
		printf("<UL>\n");
	    } else {
		printf("<P><A HREF=\"%s\">%s</A>\n<HR>\n",
		    menu_url(req, "menu"), "Cache Manager menu");
		printf("<PRE>\n");
	    }
	    istate = isBody;
	    /* yes, fall through, we do not want to loose the first line */
	case isBody:
	    /* interpret [and reformat] cache response */
	    if (parse_menu)
		fputs(munge_menu_line(buf, req), stdout);
	    else
		fputs(munge_other_line(buf, req), stdout);
	    break;
	case isForward:
	    /* forward: no modifications allowed */
	    /*
	     * Note: we currently do not know any way to get browser.reply to
	     * 401 to .cgi because web server filters out all auth info. Thus we
	     * disable authentication headers for now.
	     */
	    if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19));	/* skip */
	    else
		fputs(buf, stdout);
	    break;
	case isEof:
	    /* print trailers */
	    if (parse_menu)
		printf("</UL>\n");
	    else
		printf("</table></PRE>\n");
	    print_trailer();
	    istate = isSuccess;
	    break;
	case isForwardEof:
	    /* indicate that we finished processing an "error" sequence */
	    istate = isError;
	    break;
	default:
	    printf("%s: internal bug: invalid state reached: %d", script_name, istate);
	    istate = isError;
	}
    }
    close(s);
    return 0;
}
Ejemplo n.º 8
0
// start-line      = Request-Line | Status-Line
const char* parse_start_line(unsigned char** p)
{
	if (!parse_request_line(p))
		return NULL;
	return parse_status_line(p);
}
Ejemplo n.º 9
0
static int
read_reply(int s, cachemgr_request * req)
{
    char buf[4 * 1024];
#ifdef _SQUID_MSWIN_
    int reply;
    char *tmpfile = tempnam(NULL, "tmp0000");
    FILE *fp = fopen(tmpfile, "w+");
#else
    FILE *fp = fdopen(s, "r");
#endif
    /* interpretation states */
    enum {
	isStatusLine, isHeaders, isActions, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError
    } istate = isStatusLine;
    int parse_menu = 0;
    const char *action = req->action;
    const char *statusStr = NULL;
    int status = -1;
    if (0 == strlen(req->action))
	parse_menu = 1;
    else if (0 == strcasecmp(req->action, "menu"))
	parse_menu = 1;
    if (fp == NULL) {
#ifdef _SQUID_MSWIN_
	perror(tmpfile);
	xfree(tmpfile);
	closesocket(s);
#else
	perror("fdopen");
	close(s);
#endif
	return 1;
    }
#ifdef _SQUID_MSWIN_
    while ((reply = recv(s, buf, sizeof(buf), 0)) > 0)
	fwrite(buf, 1, reply, fp);
    rewind(fp);
#endif
    if (parse_menu)
	action = "menu";
    /* read reply interpreting one line at a time depending on state */
    while (istate < isEof) {
	if (!fgets(buf, sizeof(buf), fp))
	    istate = istate == isForward ? isForwardEof : isEof;
	switch (istate) {
	case isStatusLine:
	    /* get HTTP status */
	    /* uncomment the following if you want to debug headers */
	    /* fputs("\r\n\r\n", stdout); */
	    status = parse_status_line(buf, &statusStr);
	    istate = status == 200 ? isHeaders : isForward;
	    /* if cache asks for authentication, we have to reset our info */
	    if (status == 401 || status == 407) {
		reset_auth(req);
		status = 403;	/* Forbiden, see comments in case isForward: */
	    }
	    /* this is a way to pass HTTP status to the Web server */
	    if (statusStr)
		printf("Status: %d %s", status, statusStr);	/* statusStr has '\n' */
	    break;
	case isHeaders:
	    /* forward header field */
	    if (!strcmp(buf, "\r\n")) {		/* end of headers */
		fputs("Content-Type: text/html\r\n", stdout);	/* add our type */
		istate = isBodyStart;
	    }
	    if (strncasecmp(buf, "Content-Type:", 13))	/* filter out their type */
		fputs(buf, stdout);
	    break;
	case isBodyStart:
	    printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
	    printf("<HTML><HEAD><TITLE>CacheMgr@%s: %s</TITLE>\n",
		req->hostname, action);
	    printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}TABLE{background-color:#333333;border:0pt;padding:0pt}TH,TD{background-color:#ffffff;white-space:nowrap}--></STYLE>\n");
	    printf("</HEAD><BODY>\n");
	    if (parse_menu) {
		printf("<H2><a href=\"%s\">Cache Manager</a> menu for %s:</H2>",
		    menu_url(req, "authenticate"), req->hostname);
	    } else {
		printf("<P><A HREF=\"%s\">%s</A>\n",
		    menu_url(req, "menu"), "Cache Manager menu");
	    }
	    istate = isActions;
	    /* yes, fall through, we do not want to loose the first line */
	case isActions:
	    if (strncmp(buf, "action:", 7) == 0) {
		fputs(" ", stdout);
		fputs(munge_action_line(buf + 7, req), stdout);
		break;
	    }
	    if (parse_menu) {
		printf("<UL>\n");
	    } else {
		printf("<HR noshade size=\"1px\">\n");
		printf("<PRE>\n");
	    }
	    istate = isBody;
	    /* yes, fall through, we do not want to loose the first line */
	case isBody:
	    /* interpret [and reformat] cache response */
	    if (parse_menu)
		fputs(munge_menu_line(buf, req), stdout);
	    else
		fputs(munge_other_line(buf, req), stdout);
	    break;
	case isForward:
	    /* forward: no modifications allowed */
	    /*
	     * Note: we currently do not know any way to get browser.reply to
	     * 401 to .cgi because web server filters out all auth info. Thus we
	     * disable authentication headers for now.
	     */
	    if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19));	/* skip */
	    else
		fputs(buf, stdout);
	    break;
	case isEof:
	    /* print trailers */
	    if (parse_menu)
		printf("</UL>\n");
	    else
		printf("</table></PRE>\n");
	    print_trailer();
	    istate = isSuccess;
	    break;
	case isForwardEof:
	    /* indicate that we finished processing an "error" sequence */
	    istate = isError;
	    break;
	default:
	    printf("%s: internal bug: invalid state reached: %d", script_name, istate);
	    istate = isError;
	}
    }
#ifdef _SQUID_MSWIN_
    fclose(fp);
    remove(tmpfile);
    xfree(tmpfile);
    closesocket(s);
#else
    close(s);
#endif
    return 0;
}
Ejemplo n.º 10
0
int handle_response(char *ip, char *filename) {

    int i;

    char buffer[RESPONSE_BUFFER_SIZE];
    int buffer_size = 0;
    int pointer = 0;

    char status_line[HEADER_LINE_LENGTH];
    char header[HEADER_LINE_LENGTH];
    char value[HEADER_LINE_LENGTH];
    int status_ok;

    char header_content_length[HEADER_LINE_LENGTH];
    char header_content_type[HEADER_LINE_LENGTH];
    char header_last_modified[HEADER_LINE_LENGTH];

    time_t curtime;
    char current_time[HEADER_LINE_LENGTH];

    FILE *fp;

    /* fill buffer with first part of response */
    buffer_size = get_response_header(buffer, RESPONSE_BUFFER_SIZE);
    if (buffer_size < 0) {
        printf("Request failed: could not retrieve response from server\n");
        return 0;
    }

    /* read status line */
    pointer = parse_status_line(buffer, buffer_size, status_line,
                                HEADER_LINE_LENGTH, &status_ok);
    if (pointer < 0) {
        printf("Request failed: invalid response status code sent by server\n");
        return 0;
    }

    /* default value for headers */
    snprintf(header_content_length, HEADER_LINE_LENGTH, "Unknown");
    snprintf(header_content_type, HEADER_LINE_LENGTH, "Unknown");
    snprintf(header_last_modified, HEADER_LINE_LENGTH, "Unknown");

    /* read headers */
    while ((i = parse_header(buffer + pointer, buffer_size - pointer,
                             header, HEADER_LINE_LENGTH,
                             value, HEADER_LINE_LENGTH)) > 0) {
        pointer += i;
        if (strcmp(header, "Content-Length") == 0) {
            memcpy(header_content_length, value, HEADER_LINE_LENGTH);
        } else if (strcmp(header, "Content-Type") == 0) {
            memcpy(header_content_type, value, HEADER_LINE_LENGTH);
        } else if (strcmp(header, "Last-Modified") == 0) {
            memcpy(header_last_modified, value, HEADER_LINE_LENGTH);
        }
    }

    i = read_separator(buffer + pointer, buffer_size - pointer);
    if (i < 0) {
        printf("Request failed: invalid response sent by server\n");
        return 0;
    }
    pointer += i;

    /* get current time */
    time(&curtime);
    strftime(current_time, HEADER_LINE_LENGTH, DATE_TIME_FORMAT,
             gmtime(&curtime));

    /* print some output */
    printf("Request sent to http server at %s. Received response:\n", ip);
    printf("  The return code was:        %s\n", status_line);
    printf("  Date of retrieval:          %s\n", current_time);
    printf("  Document last modified at:  %s\n", header_last_modified);
    printf("  Document size:              %s bytes\n", header_content_length);
    printf("  Document's mime type:       %s\n", header_content_type);

    if (!status_ok) {
        printf("Since the status code was not '200 OK', no data has been written\nto %s\n",
               filename);
        return 1;
    }

    /* open file for writing */
    if ((fp = fopen(filename, "w")) == (FILE *)0) {
        switch (errno) {
            case EACCES:
                printf("No permissions to open file for writing: %s\n", filename);
                return 0;
                break;
            default:
                printf("Could not open file for writing: %s\n", filename);
                return 0;
        }
    }

    /* read until end of stream */
    do {

        /* write buffer contents to file */
        while (pointer < buffer_size) {
            putc(buffer[pointer], fp);
            pointer++;
        }

        signal(SIGALRM, alarm_handler);
        alarm(TIME_OUT);
        buffer_size = tcp_read(buffer, RESPONSE_BUFFER_SIZE);
        alarm(0);

        /* failed reading */
        if (buffer_size < 0
            || alarm_went_off) {
            /*
              Actually, we should write to a temp file
              and delete it here. Only if all data is
              received, copy temp file to real file.
              But this is a problem if we have write
              rights on filename, but not to create
              temp file. So we leave this for the time
              being.                  
            */
            fclose(fp);
            printf("Request failed: could not retrieve message body\n");
            printf("Wrote partial message body to file: %s\n", filename);
            return 0;
        }

        pointer = 0;

    } while (buffer_size);

    fclose(fp);

    printf("Wrote message body to file: %s\n", filename);

    return 1;

}
Ejemplo n.º 11
0
/* ========================================================================= */
struct query *read_request(struct query *q, int s, struct iobuf *b)
{
   size_t offset; 
   ssize_t got;
   int recvmore;
   char uri[MAX_URI_LENGTH];
   int method;

   offset = 0;
   recvmore = 1;
   while ( recvmore )
   {
      got = recv(s, b->buf + offset, b->size - offset, 0);

      if ( got < 0 )
      {
         if ( errno != EINTR )
         {
            if ( q )
               q->parse_failure |= UP_DEAD_SOCKET;
            else
            {
               /* NOTE:
                    ParseURLString() will allocate and initialize q if it is NULL.
                    So... it is possible that q might be NULL here. If it is, then
                    allocate it so we can pass the specific error. */
               if ( NULL == (q = (struct query *)malloc(sizeof(struct query))) )
               {
                  error_msg("ERROR: Failed to allocate memory for a query.");
                  pthread_exit((void *)1);
               }

               q->parse_failure = UP_DEAD_SOCKET;
            }

            error_msg("ERROR: Dropped connection on recv() call.\n");
            return(q);
         }
      }
      else
      {
         offset += got;
         b->eod += got;
         
         if ( got == 0 )
         {
            /* This should never happen */
            if ( offset > 10 ) /* Arbitrary number *somewhat* large enough to hold a request */
            {
               if (( b->buf[offset - 4] == '\r' ) &&
                   ( b->buf[offset - 3] == '\n' ) &&
                   ( b->buf[offset - 2] == '\r' ) &&
                   ( b->buf[offset - 1] == '\n' ))
               {
                  recvmore = 0;

                  parse_status_line(&method, uri, b->buf);
               }
            } /* If some data ( > 10 ) */
         }
         else
         {
            if ( offset > 10 ) /* Arbitrary number *somewhat* large enough to hold a request */
            {
               if (( b->buf[offset - 4] == '\r' ) &&
                   ( b->buf[offset - 3] == '\n' ) &&
                   ( b->buf[offset - 2] == '\r' ) &&
                   ( b->buf[offset - 1] == '\n' ))
               {
                  recvmore = 0;

                  parse_status_line(&method, uri, b->buf);
               }

            } /* If some data ( > 10 ) */
         } /* if ( got == 0 ) else */
      } /* if ( got < 0 ) else */
   } /* while recvmore */


   b->buf[b->eod] = 0; /* Terminate for safety */





   /* STUB: Enable this to see the http request header
      




      DEBUG_STUB("%s", b->buf);




   */

   switch(method)
   {
   case METHOD_GET:
      q = ParseURLString(q, uri);
      q->method = METHOD_GET;
      break;
   case METHOD_HEAD:
      q = ParseURLString(q, uri);
      q->method = METHOD_HEAD;
      break;
   case METHOD_OPTIONS:
      q = ParseURLString(q, NULL);         /* This insures that q has been allocated */
      q->method = METHOD_OPTIONS;
      break;
   case METHOD_POST:
      q = ParseURLString(q, uri);
      q->method = METHOD_POST;
      break;
   default:
      error_msg("ERROR: Unsupported request method.\n");
      q = ParseURLString(q, NULL);         /* This insures that q has been allocated */
      q->parse_failure |= UP_BAD_METHOD;
      break;
   }

   return(q);
}
Ejemplo n.º 12
0
bool net::internet::http::analyzer::process(time_t t, connection* conn, const packet& pkt)
{
	if (conn->state == kIgnoringConnection) {
		return true;
	}

	const unsigned char* begin;
	size_t count;

	if (pkt.direction == kOutgoingPacket) {
		if (conn->state >= kParsingStatusLine) {
			return true;
		}

		count = conn->out ? conn->out->count() : 0;

		if (!conn->append_out(reinterpret_cast<const char*>(pkt.payload), pkt.len)) {
			return false;
		}

		begin = reinterpret_cast<const unsigned char*>(conn->out->data()) + count;
	} else {
		if (conn->state < kParsingStatusLine) {
			return true;
		}

		count = conn->in ? conn->in->count() : 0;

		if (!conn->append_in(reinterpret_cast<const char*>(pkt.payload), pkt.len)) {
			return false;
		}

		begin = reinterpret_cast<const unsigned char*>(conn->in->data()) + count;
	}

	count += pkt.len;

	const unsigned char* ptr = begin;
	const unsigned char* end = ptr + pkt.len;

	size_t methodlen = conn->protocol.http.methodlen;
	size_t pathlen = conn->protocol.http.pathlen;
	size_t hostlen = conn->protocol.http.hostlen;

	int state = conn->state;

	do {
		unsigned char c = *ptr;

		switch (state) {
			case kBeforeMethod: // Before method.
				if ((c >= 'A') && (c <= 'Z')) {
					conn->protocol.http.method = count - (end - ptr);
					methodlen = 1;

					state = kMethod; // Method.
				} else if ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n')) {
					// Ignore connection.
					conn->state = kIgnoringConnection;
					return true;
				}

				break;
			case kMethod: // Method.
				if ((c >= 'A') && (c <= 'Z')) {
					if (++methodlen > kMethodMaxLen) {
						// Ignore connection.
						conn->state = kIgnoringConnection;
						return true;
					}
				} else if ((c == ' ') || (c == '\t')) {
					conn->protocol.http.methodlen = methodlen;

					state = kBeforePath; // Before path.
				} else {
					// Ignore connection.
					conn->state = kIgnoringConnection;
					return true;
				}

				break;
			case kBeforePath: // Before path.
				if (c > ' ') {
					conn->protocol.http.path = count - (end - ptr);
					pathlen = 1;

					state = kPath; // Path.
				} else if ((c != ' ') && (c != '\t')) {
					// Ignore connection.
					conn->state = kIgnoringConnection;
					return true;
				}

				break;
			case kPath: // Path.
				switch (c) {
					case ' ':
					case '\t':
					case '\r':
					case '\n':
						conn->protocol.http.pathlen = pathlen;

						if ((pathlen > 7) && (strncasecmp(conn->out->data() + conn->protocol.http.path, "http://", 7) == 0)) {
							conn->protocol.http.host = 0;

							conn->protocol.http.offset = 0;

							conn->state = kParsingStatusLine;
							conn->protocol.http.substate = 0;

							return true;
						}

						state = kSearchingHost; // Searching host.

						break;
					default:
						if (c > ' ') {
							if (++pathlen > kPathMaxLen) {
								// Ignore connection.
								conn->state = kIgnoringConnection;
								return true;
							}
						} else {
							// Ignore connection.
							conn->state = kIgnoringConnection;
							return true;
						}
				}

				break;
			case kSearchingHost: // Searching host.
				ptr = reinterpret_cast<const unsigned char*>(conn->out->data()) + conn->protocol.http.path + conn->protocol.http.pathlen;

				if ((ptr = reinterpret_cast<const unsigned char*>(memmem(ptr, end - ptr, "Host:", 5))) == NULL) {
					// Host header might come in the next packet.
					ptr = end;

					continue;
				} else {
					ptr += 5;

					state = kBeforeHostValue; // Before host value.

					continue;
				}

				break;
			case kBeforeHostValue: // Before host value.
				if (c > ' ') {
					conn->protocol.http.host = count - (end - ptr);
					hostlen = 1;

					state = kHost; // Host.
				} else if ((c != ' ') && (c != '\t')) {
					// Ignore connection.
					conn->state = kIgnoringConnection;
					return true;
				}

				break;
			case kHost: // Host.
				switch (c) {
					case ' ':
					case '\t':
					case '\r':
					case '\n':
						conn->protocol.http.hostlen = hostlen;

						conn->protocol.http.offset = 0;

						conn->state = kParsingStatusLine;
						conn->protocol.http.substate = 0;

						return true;
					default:
						if (c > ' ') {
							if (++hostlen > kHostMaxLen) {
								// Ignore connection.
								conn->state = kIgnoringConnection;
								return true;
							}
						} else {
							// Ignore connection.
							conn->state = kIgnoringConnection;
							return true;
						}
				}

				break;
			case kParsingStatusLine: // Parsing status-line.
				switch (parse_status_line(conn)) {
					case kParseError:
						// Ignore connection.
						conn->state = kIgnoringConnection;
						return true;
					case kParsingNotCompleted:
						return true;
					case kParsingCompleted:
						ptr = reinterpret_cast<const unsigned char*>(conn->in->data()) + conn->protocol.http.offset;

						state = kParsingServerHeaders;
						continue;
				}

				break;
			case kParsingServerHeaders: // Parsing server headers.
				switch (conn->protocol.http.parse_server_headers(conn->in->data() + conn->protocol.http.offset, count - conn->protocol.http.offset)) {
					case headers::PARSE_NO_MEMORY:
					case headers::PARSE_INVALID_HEADER:
					case headers::PARSE_HEADERS_TOO_LARGE:
						// Ignore connection.
						conn->state = kIgnoringConnection;
						return true;
					case headers::PARSE_NOT_END_OF_HEADER:
						return true;
					case headers::PARSE_END_OF_HEADER:
						if (!gsniffer.get_http_logger()->log(t, conn)) {
							return false;
						}

						conn->state = kIgnoringConnection;
						return true;
				}

				break;
		}

		ptr++;
	} while (ptr < end);

	if (pkt.direction == kOutgoingPacket) {
		// Request too large?
		if (count > kRequestMaxLen) {
			// Ignore connection.
			conn->state = kIgnoringConnection;
			return true;
		}
	}

	conn->state = state;

	conn->protocol.http.methodlen = methodlen;
	conn->protocol.http.pathlen = pathlen;
	conn->protocol.http.hostlen = hostlen;

	return true;
}
/* Perform one iteration of the state machine.
 *
 * Will return when one the following conditions occurred:
 *  1) a state change
 *  2) an error
 *  3) the stream is not ready or at EOF
 *  4) APR_SUCCESS, meaning the machine can be run again immediately
 */
static apr_status_t run_machine(serf_bucket_t *bkt, response_context_t *ctx)
{
    apr_status_t status = APR_SUCCESS; /* initialize to avoid gcc warnings */

    switch (ctx->state) {
    case STATE_STATUS_LINE:
        /* RFC 2616 says that CRLF is the only line ending, but we can easily
         * accept any kind of line ending.
         */
        status = fetch_line(ctx, SERF_NEWLINE_ANY);
        if (SERF_BUCKET_READ_ERROR(status))
            return status;

        if (ctx->linebuf.state == SERF_LINEBUF_READY) {
            /* The Status-Line is in the line buffer. Process it. */
            status = parse_status_line(ctx, bkt->allocator);
            if (status)
                return status;

            /* Good times ahead: we're switching protocols! */
            if (ctx->sl.code == 101) {
                ctx->body =
                    serf_bucket_barrier_create(ctx->stream, bkt->allocator);
                ctx->state = STATE_DONE;
                break;
            }

            /* Okay... move on to reading the headers. */
            ctx->state = STATE_HEADERS;
        }
        else {
            /* The connection closed before we could get the next
             * response.  Treat the request as lost so that our upper
             * end knows the server never tried to give us a response.
             */
            if (APR_STATUS_IS_EOF(status)) {
                return SERF_ERROR_REQUEST_LOST;
            }
        }
        break;
    case STATE_HEADERS:
        status = fetch_headers(bkt, ctx);
        if (SERF_BUCKET_READ_ERROR(status))
            return status;

        /* If an empty line was read, then we hit the end of the headers.
         * Move on to the body.
         */
        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
            const void *v;

            /* Advance the state. */
            ctx->state = STATE_BODY;

            ctx->body =
                serf_bucket_barrier_create(ctx->stream, bkt->allocator);

            /*
             * Instaweb/mod_pagespeed change: This section is
             * re-ordered from the original code from serf to Follow
             * HTTP spec by checking "Transfer-Encoding: chunked",
             * before "Content-Length".
             */

            /* Are we C-L, chunked, or conn close? */
            v = serf_bucket_headers_get(ctx->headers, "Transfer-Encoding");

            /* Need to handle multiple transfer-encoding. */
            if (v && strcasecmp("chunked", v) == 0) {
                ctx->chunked = 1;
                ctx->body = serf_bucket_dechunk_create(ctx->body,
                                                       bkt->allocator);
            }
            else {
                v = serf_bucket_headers_get(ctx->headers, "Content-Length");
                if (v) {
                    apr_uint64_t length;
                    length = apr_strtoi64(v, NULL, 10);
                    if (errno == ERANGE) {
                        return APR_FROM_OS_ERROR(ERANGE);
                    }
                    ctx->body = serf_bucket_limit_create(ctx->body, length,
                                                         bkt->allocator);
                }
                else if ((ctx->sl.code == 204 || ctx->sl.code == 304)) {
                    ctx->state = STATE_DONE;
                }
            }

            /*
             * Instaweb would prefer to receive gzipped output if that's what
             * was asked for.
             *
             * v = serf_bucket_headers_get(ctx->headers, "Content-Encoding");
             * if (v) {
             *   * Need to handle multiple content-encoding. *
             *  if (v && strcasecmp("gzip", v) == 0) {
             *      ctx->body =
             *          serf_bucket_deflate_create(ctx->body, bkt->allocator,
             *                                     SERF_DEFLATE_GZIP);
             *  }
             *  else if (v && strcasecmp("deflate", v) == 0) {
             *      ctx->body =
             *          serf_bucket_deflate_create(ctx->body, bkt->allocator,
             *                                     SERF_DEFLATE_DEFLATE);
             *  }
             * }
             */

            /* If we're a HEAD request, we don't receive a body. */
            if (ctx->head_req) {
                ctx->state = STATE_DONE;
            }
        }
        break;
    case STATE_BODY:
        /* Don't do anything. */
        break;
    case STATE_TRAILERS:
        status = fetch_headers(bkt, ctx);
        if (SERF_BUCKET_READ_ERROR(status))
            return status;

        /* If an empty line was read, then we're done. */
        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
            ctx->state = STATE_DONE;
            return APR_EOF;
        }
        break;
    case STATE_DONE:
        return APR_EOF;
    default:
        /* Not reachable */
        return APR_EGENERAL;
    }

    return status;
}