Esempio n. 1
0
/* This is a convenience wrapper around http_parse_status_line that only returns
   the status code. Returns the status code on success or -1 on failure. */
int http_parse_status_line_code(const char *line)
{
    struct http_response resp;
    int code;

    if (http_parse_status_line(line, &resp) != 0)
        return -1;
    code = resp.code;
    http_response_free(&resp);

    return code;
}
Esempio n. 2
0
/**
 * NAME: sc_sohu_download
 *
 * DESCRIPTION:
 *      下载搜狐视频。
 *
 * @file_url:    -IN 搜狐视频file型url。
 * @url_id:      -IN 视频的url ID。
 *
 * RETURN: -1表示失败,0表示成功。
 */
int sc_sohu_download(char *file_url, ngx_int_t url_id)
{
    char response[BUFFER_LEN];
    char real_url[HTTP_SP_URL_LEN_MAX];
    int status, ret;
    int response_len;

    if (file_url == NULL || url_id < 0) {
        return -1;
    }

    bzero(response, sizeof(response));
    if (sohu_http_session(file_url, response, BUFFER_LEN) < 0) {
        hc_log_error("sohu_http_session faild, url: %s", file_url);
        return -1;
    }

    response_len = strlen(response);
    if (http_parse_status_line(response, response_len, &status) < 0) {
        hc_log_error("parse status line failed:\n%s", response);
        return -1;
    }

    if (status == NGX_HTTP_MOVED_PERMANENTLY) {
        (void)0;
    } else if (status == NGX_HTTP_MOVED_TEMPORARILY && strstr(response, HTTP_REDIRECT_URL)) {
        hc_log_debug("resource is already cached, url: %s", file_url);
        return 0;
    } else {
        hc_log_error("file_url response status code %d:\n%s", status, response);
        return -1;
    }

    bzero(real_url, HTTP_SP_URL_LEN_MAX);
    ret = sohu_parse_file_url_response(response, real_url);
    if (ret != 0) {
        hc_log_error("parse real_url failed, response is\n%s", response);
        return -1;
    }

    ret = sc_ngx_download(real_url, url_id);
    if (ret < 0) {
        hc_log_error("inform Nginx failed, url: %s", real_url);
    }

    return ret;
}
/* Do a GET, HEAD, or POST transaction. */
static int do_transaction(struct http_request *request,
    struct socket_buffer *client_sock, struct socket_buffer *server_sock)
{
    char buf[BUFSIZ];
    struct http_response response;
    char *line;
    char *request_str, *response_str;
    size_t len;
    int code, n;

    /* We don't handle the chunked transfer encoding, which in the absence of a
       Content-Length is the only way we know the end of a request body. RFC
       2616, section 4.4 says, "If a request contains a message-body and a
       Content-Length is not given, the server SHOULD respond with 400 (bad
       request) if it cannot determine the length of the message, or with 411
       (length required) if it wishes to insist on receiving a valid
       Content-Length." */
    if (strcmp(request->method, "POST") == 0 && request->content_length == 0) {
        if (o.debug)
            logdebug("POST request with no Content-Length.\n");
        return 400;
    }

    /* The version we use to talk to the server. */
    request->version = HTTP_10;

    /* Remove headers that only apply to our connection with the client. */
    code = http_header_remove_hop_by_hop(&request->header);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error removing hop-by-hop headers.\n");
        return code;
    }

    /* Build the Host header. */
    if (request->uri.port == -1 || request->uri.port == 80)
        n = Snprintf(buf, sizeof(buf), "%s", request->uri.host);
    else
        n = Snprintf(buf, sizeof(buf), "%s:%hu", request->uri.host, request->uri.port);
    if (n < 0 || n >= sizeof(buf)) {
        /* Request Entity Too Large. */
        return 501;
    }
    request->header = http_header_set(request->header, "Host", buf);

    request->header = http_header_set(request->header, "Connection", "close");

    /* Send the request to the server. */
    request_str = http_request_to_string(request, &len);
    n = send(server_sock->fdn.fd, request_str, len, 0);
    free(request_str);
    if (n < 0)
        return 504;
    /* Send the request body, if any. Count up to Content-Length. */
    while (request->bytes_transferred < request->content_length) {
        n = socket_buffer_read(client_sock, buf, MIN(sizeof(buf), request->content_length - request->bytes_transferred));
        if (n < 0)
            return 504;
        if (n == 0)
            break;
        request->bytes_transferred += n;
        n = send(server_sock->fdn.fd, buf, n, 0);
        if (n < 0)
            return 504;
    }
    if (o.debug && request->bytes_transferred < request->content_length)
        logdebug("Received only %lu request body bytes (Content-Length was %lu).\n", request->bytes_transferred, request->content_length);


    /* Read the response. */
    code = http_read_status_line(server_sock, &line);
    if (o.debug > 1)
        logdebug("Status-Line: %s", line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error reading Status-Line.\n");
        return 0;
    }
    code = http_parse_status_line(line, &response);
    free(line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error parsing Status-Line.\n");
        return 0;
    }

    code = http_read_header(server_sock, &line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error reading header.\n");
        return 0;
    }
    if (o.debug > 1)
        logdebug("Response header:\n%s", line);

    code = http_response_parse_header(&response, line);
    free(line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error parsing response header.\n");
        return 0;
    }


    /* The version we use to talk to the client. */
    response.version = HTTP_10;

    /* Remove headers that only apply to our connection with the server. */
    code = http_header_remove_hop_by_hop(&response.header);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error removing hop-by-hop headers.\n");
        return code;
    }

    response.header = http_header_set(response.header, "Connection", "close");

    /* Send the response to the client. */
    response_str = http_response_to_string(&response, &len);
    n = fdinfo_send(&client_sock->fdn, response_str, len);
    free(response_str);
    if (n < 0) {
        http_response_free(&response);
        return 504;
    }
    /* If the Content-Length is 0, read until the connection is closed.
       Otherwise read until the Content-Length. At this point it's too late to
       return our own error code so return 0 in case of any error. */
    while (response.content_length == 0
        || response.bytes_transferred < response.content_length) {
        size_t remaining = response.content_length - response.bytes_transferred;
        size_t count;

        count = sizeof(buf);
        if (response.content_length > 0 && remaining < count)
            count = remaining;
        n = socket_buffer_read(server_sock, buf, count);
        if (n <= 0)
            break;
        response.bytes_transferred += n;
        n = fdinfo_send(&client_sock->fdn, buf, n);
        if (n < 0)
            break;
    }

    http_response_free(&response);

    return 0;
}
Esempio n. 4
0
int
http_parse_header_line(struct http_parser *prsr, char **bufp,
		       const char *end_buf, int max_hname_len)
{
	char c, ch;
	char *p = *bufp;
	char *header_name_start = p;
	prsr->hdr_name_idx = 0;

	enum {
		sw_start = 0,
		skip_status_line,
		skipped_status_line_almost_done,
		sw_name,
		sw_space_before_value,
		sw_value,
		sw_space_after_value,
		sw_almost_done,
		sw_header_almost_done
	} state = sw_start;

	/*
	 * The last '\0' is not needed
	 * because string is zero terminated
	 */
	static char lowcase[] =
			"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
			"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789"
			"\0\0\0\0\0\0\0abcdefghijklmnopqrstuvwxyz\0\0\0\0_\0"
			"abcdefghijklmnopqrstuvwxyz\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
			"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
			"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
			"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
			"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
			"\0\0\0\0\0\0\0\0\0\0";

	for (; p < end_buf; p++) {
		ch = *p;
		switch (state) {
		/* first char */
		case sw_start:
			switch (ch) {
			case CR:
				prsr->hdr_value_end = p;
				state = sw_header_almost_done;
				break;
			case LF:
				prsr->hdr_value_end = p;
				goto header_done;
			default:
				state = sw_name;

				c = lowcase[ch];
				if (c != 0) {
					prsr->hdr_name[0] = c;
					prsr->hdr_name_idx = 1;
					break;
				}
				if (ch == '\0') {
					return HTTP_PARSE_INVALID;
				}
				break;
			}
			break;
		case skip_status_line:
			switch (ch) {
			case LF:
				goto skipped_status;
			case CR:
				state = skipped_status_line_almost_done;
			default:
				break;
			}
			break;
		case skipped_status_line_almost_done:
			switch (ch) {
			case LF:
				goto skipped_status;
			case CR:
				break;
			default:
				return HTTP_PARSE_INVALID;
			}
			break;
		/* http_header name */
		case sw_name:
			c = lowcase[ch];
			if (c != 0) {
				if (prsr->hdr_name_idx < max_hname_len) {
					prsr->hdr_name[prsr->hdr_name_idx] = c;
					prsr->hdr_name_idx++;
				}
				break;
			}
			if (ch == ':') {
				state = sw_space_before_value;
				break;
			}
			if (ch == CR) {
				prsr->hdr_value_start = p;
				prsr->hdr_value_end = p;
				state = sw_almost_done;
				break;
			}
			if (ch == LF) {
				prsr->hdr_value_start = p;
				prsr->hdr_value_end = p;
				goto done;
			}
			/* handle "HTTP/1.1 ..." lines */
			if (ch == '/' && p - header_name_start == 4 &&
				strncmp(header_name_start, "HTTP", 4) == 0) {
				int rc = http_parse_status_line(prsr,
							&header_name_start,
							end_buf);
				if (rc == HTTP_PARSE_INVALID) {
					prsr->http_minor = -1;
					prsr->http_major = -1;
					state = sw_start;
				} else {
					/* Skip it till end of line. */
					state = skip_status_line;
				}
				break;
			}
			if (ch == '\0')
				return HTTP_PARSE_INVALID;
			break;
		/* space* before http_header value */
		case sw_space_before_value:
			switch (ch) {
			case ' ':
				break;
			case CR:
				prsr->hdr_value_start = p;
				prsr->hdr_value_end = p;
				state = sw_almost_done;
				break;
			case LF:
				prsr->hdr_value_start = p;
				prsr->hdr_value_end = p;
				goto done;
			case '\0':
				return HTTP_PARSE_INVALID;
			default:
				prsr->hdr_value_start = p;
				state = sw_value;
				break;
			}
			break;

		/* http_header value */
		case sw_value:
			switch (ch) {
			case ' ':
				prsr->hdr_value_end = p;
				state = sw_space_after_value;
				break;
			case CR:
				prsr->hdr_value_end = p;
				state = sw_almost_done;
				break;
			case LF:
				prsr->hdr_value_end = p;
				goto done;
			case '\0':
				return HTTP_PARSE_INVALID;
			}
			break;
		/* space* before end of http_header line */
		case sw_space_after_value:
			switch (ch) {
			case ' ':
				break;
			case CR:
				state = sw_almost_done;
				break;
			case LF:
				goto done;
			case '\0':
				return HTTP_PARSE_INVALID;
			default:
				state = sw_value;
				break;
			}
			break;
		/* end of http_header line */
		case sw_almost_done:
			switch (ch) {
			case LF:
				goto done;
			case CR:
				break;
			default:
				return HTTP_PARSE_INVALID;
			}
			break;
		/* end of http_header */
		case sw_header_almost_done:
			if (ch == LF)
				goto header_done;
			else
				return HTTP_PARSE_INVALID;
		}
	}

skipped_status:
	*bufp = p + 1;
	return HTTP_PARSE_CONTINUE;

done:
	*bufp = p + 1;
	return HTTP_PARSE_OK;

header_done:
	*bufp = p + 1;
	return HTTP_PARSE_DONE;
}
Esempio n. 5
0
/*
 * 各种url举例:
 * m3u8_url:   hot.vrs.sohu.com/ipad1683703_4507722770245_4894024.m3u8?plat=0
 * file_url:   220.181.61.212/ipad?file=/109/193/XKUNcCADy8eM9ypkrIfhU4.mp4
 * local_path: 220.181.61.212/ipad_file=_109_193_XKUNcCADy8eM9ypkrIfhU4.mp4
 * real_url:   118.123.211.11/sohu/ts/zC1LzEwlslvesEAgoE.........
 */
static int sc_get_sohu_video_m3u8(char *origin_url)
{
    int err = 0, status, ret;
    char m3u8_url[HTTP_SP_URL_LEN_MAX];
    char file_url[HTTP_SP_URL_LEN_MAX];
    char *response = NULL, *curr;
    int response_len;
    ngx_str_t url_str;
    ngx_int_t url_id;

    if (origin_url == NULL) {
        hc_log_error("invalid input.");
        return -1;
    }

    memset(m3u8_url, 0, HTTP_SP_URL_LEN_MAX);
    sc_copy_url(m3u8_url, origin_url, HTTP_SP_URL_LEN_MAX, 0);

    response = rgos_malloc(RESP_BUF_LEN);
    if (response == NULL) {
        hc_log_error("allocate response buffer (%d bytes) failed", RESP_BUF_LEN);
        return -1;
    }

    bzero(response, RESP_BUF_LEN);
    if (sohu_http_session(m3u8_url, response, RESP_BUF_LEN) < 0) {
        hc_log_error("sohu_http_session faild, URL: %s", m3u8_url);
        err = -1;
        goto out;
    }

    response_len = strlen(response);
    if (http_parse_status_line(response, response_len, &status) < 0) {
        hc_log_error("parse status line failed:\n%s", response);
        err = -1;
        goto out;
    }

    if (status == NGX_HTTP_OK) {
        (void)0;
    } else {
        hc_log_error("m3u8 response status code %d:\n%s", status, response);
        err = -1;
        goto out;
    }

    for (curr = response; curr != NULL; ) {
        bzero(file_url, HTTP_SP_URL_LEN_MAX);
        curr = sohu_parse_m3u8_response(curr, file_url);

        url_str.data = (u_char *)file_url;
        url_str.len = strlen(file_url);
        /* 调用Snooping Module提供的接口,添加url */
        url_id = ngx_http_sp_url_handle(&url_str, HTTP_C2SP_ACTION_ADD);
        if (url_id < 0) {
            /* TODO: 以前添加成功的url怎么办? */
            hc_log_error("add url to Snooping Module failed: %s", file_url);
            continue;
        }

        ret = sc_sohu_download(file_url, url_id);
        if (ret != 0) {
            hc_log_error("sc_sohu_download failed, file url: %s", file_url);
            ngx_http_sp_url_state_setby_id(url_id, HTTP_LOCAL_DOWN_STATE_ERROR);
            continue;
        }
    }

out:
    rgos_free(response);

    return err;
}
Esempio n. 6
0
int http_parser_input(void* parser, const void* data, size_t *bytes)
{
	enum { INPUT_NEEDMORE = 1, INPUT_DONE = 0, };

	int r;
	struct http_context *ctx;
	ctx = (struct http_context*)parser;

	// save raw data
	r = http_rawdata(ctx, data, *bytes);
	if(0 != r)
	{
		assert(r < 0);
		return r;
	}

	if(SM_FIRSTLINE <= ctx->stateM && ctx->stateM < SM_HEADER)
	{
		r = is_server_mode(ctx) ? http_parse_request_line(ctx) : http_parse_status_line(ctx);
	}

	if(SM_HEADER <= ctx->stateM && ctx->stateM < SM_BODY)
	{
		r = http_parse_header_line(ctx);
	}

	assert(r <= 0);
	if(SM_BODY <= ctx->stateM && ctx->stateM < SM_DONE)
	{
		if(is_transfer_encoding_chunked(ctx))
		{
			r = http_parse_chunked(ctx);
		}
		else
		{
			if(-1 == ctx->content_length)
			{
				if(is_server_mode(ctx))
				{
					ctx->content_length = 0;
					ctx->stateM = SM_DONE;
				}
				else
				{
					// H4.4 Message Length, section 5, server closing the connection
					// receive all until socket closed
					assert(!is_server_mode(ctx));
					if(0 == *bytes /*|| ctx->raw_size == ctx->offset*/)
					{
						ctx->content_length = ctx->raw_size - ctx->offset;
						ctx->stateM = SM_DONE;
					}
				}
			}
			else
			{
				assert(ctx->raw_size <= ctx->offset + ctx->content_length);
				if(ctx->raw_size >= ctx->offset + ctx->content_length)
					ctx->stateM = SM_DONE;
			}
		}
	}

	if(r < 0)
		return r;

	*bytes = 0;
	return ctx->stateM == SM_DONE ? INPUT_DONE : INPUT_NEEDMORE;
}