コード例 #1
0
ファイル: uri.c プロジェクト: lubing521/libhttp
static int
http_uri_finalize(struct http_uri *uri) {
    if (!uri->port && uri->scheme) {
        if (strcasecmp(uri->scheme, "http") == 0) {
            uri->port = http_strdup("80");
        } else if (strcasecmp(uri->scheme, "https") == 0) {
            uri->port = http_strdup("443");
        }
    }

    return 0;
}
コード例 #2
0
ファイル: uri.c プロジェクト: lubing521/libhttp
void
http_uri_set_fragment(struct http_uri *uri, const char *fragment) {
    if (uri->fragment)
        http_free(uri->fragment);

    uri->fragment = http_strdup(fragment);
}
コード例 #3
0
ファイル: uri.c プロジェクト: lubing521/libhttp
void
http_uri_set_port(struct http_uri *uri, const char *port) {
    if (uri->port)
        http_free(uri->port);

    uri->port = http_strdup(port);
}
コード例 #4
0
ファイル: uri.c プロジェクト: lubing521/libhttp
void
http_uri_set_path(struct http_uri *uri, const char *path) {
    if (uri->path)
        http_free(uri->path);

    uri->path = http_strdup(path);
}
コード例 #5
0
ファイル: uri.c プロジェクト: lubing521/libhttp
void
http_uri_set_password(struct http_uri *uri, const char *password) {
    if (uri->password)
        http_free(uri->password);

    uri->password = http_strdup(password);
}
コード例 #6
0
ファイル: uri.c プロジェクト: lubing521/libhttp
void
http_uri_set_host(struct http_uri *uri, const char *host) {
    if (uri->host)
        http_free(uri->host);

    uri->host = http_strdup(host);
}
コード例 #7
0
ファイル: uri.c プロジェクト: lubing521/libhttp
void
http_uri_set_user(struct http_uri *uri, const char *user) {
    if (uri->user)
        http_free(uri->user);

    uri->user = http_strdup(user);
}
コード例 #8
0
ファイル: uri.c プロジェクト: lubing521/libhttp
void
http_uri_set_scheme(struct http_uri *uri, const char *scheme) {
    if (uri->scheme)
        http_free(uri->scheme);

    uri->scheme = http_strdup(scheme);
}
コード例 #9
0
ファイル: uri.c プロジェクト: lubing521/libhttp
void
http_uri_add_query_parameter(struct http_uri *uri,
                             const char *name, const char *value) {
    struct http_query_parameter *parameters, *parameter;

    if (uri->nb_query_parameters == 0) {
        parameters = http_malloc(sizeof(struct http_query_parameter));
    } else {
        size_t nsz;

        nsz = (uri->nb_query_parameters + 1)
            * sizeof(struct http_query_parameter);
        parameters = http_realloc(uri->query_parameters, nsz);
    }

    parameter = parameters + uri->nb_query_parameters;
    parameter->name = http_strdup(name);
    parameter->value = http_strdup(value);

    uri->query_parameters = parameters;
    uri->nb_query_parameters++;
}
コード例 #10
0
ファイル: routes.c プロジェクト: lubing521/libhttp
struct http_route *
http_route_new(enum http_method method, const char *path,
               http_msg_handler msg_handler) {
    struct http_route *route;

    route = http_malloc0(sizeof(struct http_route));

    route->method = method;
    route->path = http_strdup(path);
    route->msg_handler = msg_handler;

    if (http_route_components_parse(path, &route->components,
                                    &route->nb_components) == -1) {
        http_route_delete(route);
        return NULL;
    }

    return route;
}
コード例 #11
0
ファイル: uri.c プロジェクト: lubing521/libhttp
static int
http_uri_parse(const char *str, struct http_uri *uri) {
    const char *ptr, *start, *colon;
    size_t toklen;

    memset(uri, 0, sizeof(struct http_uri));

    ptr = str;

    if (*ptr == '\0') {
        http_set_error("empty string");
        return -1;
    }

    /* Scheme */
    start = ptr;

    if (*ptr == '/') {
        goto path;
    } else if (!(*ptr >= 'a' && *ptr <= 'z')
            && !(*ptr >= 'A' && *ptr <= 'Z')
            && *ptr != '%') {
        http_set_error("invalid first character \\%hhu in scheme",
                       (unsigned char)*ptr);
        return -1;
    }

    for (;;) {
        if (*ptr == ':' || *ptr == '\0') {
            toklen = (size_t)(ptr - start);
            uri->scheme = http_uri_decode_component(start, toklen);
            if (!uri->scheme)
                return -1;

            break;
        } else if (!http_uri_is_scheme_char((unsigned char)*ptr)
                && *ptr != '%') {
            http_set_error("invalid character \\%hhu in scheme",
                           (unsigned char)*ptr);
            return -1;
        }

        ptr++;
    }

    /* Skip '://' */
    if (ptr[0] != ':' || ptr[1] != '/' || ptr[2] != '/') {
        http_set_error("invalid characters after scheme");
        return -1;
    }

    ptr += 3;

    /* User (optional) */
    start = ptr;
    colon = NULL;
    while (*ptr != '\0') {
        if (*ptr == ':') {
            colon = ptr;
        } else if (*ptr == '@') {
            if (colon) {
                toklen = (size_t)(colon - start);
            } else {
                toklen = (size_t)(ptr - start);
            }

            uri->user = http_uri_decode_component(start, toklen);
            if (!uri->user)
                return -1;

            if (colon)
                ptr = colon;
            break;
        } else if (*ptr == '/') {
            /* End of authority, no user found */
            break;
        }

        ptr++;
    }

    if (!uri->user) {
        /* Since we did not find a username, we backtrack to read the host. */
        ptr = start;
    }

    /* Password (optional) */
    if (uri->user && *ptr == ':') {
        start = ptr;

        for (;;) {
            if (*ptr == '@' || *ptr == '\0') {
                toklen = (size_t)(ptr - start - 1);
                if (toklen == 0) {
                    http_set_error("empty password");
                    return -1;
                }

                uri->password = http_uri_decode_component(start + 1, toklen);
                if (!uri->password)
                    return -1;

                break;
            } else if (*ptr == '/') {
                /* End of authority, no password found */
                break;
            }

            ptr++;
        }

        if (!uri->password) {
            http_set_error("empty password");
            return -1;
        }
    }

    if (uri->user) {
        /* Skip '@' */
        ptr++;
    }

    /* Host */
    start = ptr;
    if (*start >= '0' && *start <= '9') {
        /* IPv4 address */
        for (;;) {
            if (*ptr == '/' || *ptr == ':' || *ptr == '\0') {
                toklen = (size_t)(ptr - start);
                if (toklen == 0) {
                    http_set_error("empty host");
                    return -1;
                }

                uri->host = http_uri_decode_component(start, toklen);
                if (!uri->host)
                    return -1;

                break;
            } else if (!http_uri_is_ipv4_addr_char((unsigned char)*ptr)) {
                http_set_error("invalid character \\%hhu in ipv4 address",
                               (unsigned char)*ptr);
                return -1;
            }

            ptr++;
        }
    } else if (*start == '[') {
        ptr++; /* '[' */
        start = ptr;

        /* IPv6 address */
        for (;;) {
            if (*ptr == ']') {
                toklen = (size_t)(ptr - start);
                if (toklen == 0) {
                    http_set_error("empty host");
                    return -1;
                }

                uri->host = http_uri_decode_component(start, toklen);
                if (!uri->host)
                    return -1;

                ptr++; /* ']' */

                break;
            } else if (*ptr == '\0') {
                http_set_error("truncated ipv6 address");
                return -1;
            } else if (!http_uri_is_ipv6_addr_char((unsigned char)*ptr)) {
                http_set_error("invalid character \\%hhu in ipv6 address",
                               (unsigned char)*ptr);
                return -1;
            }

            ptr++;
        }
    } else {
        /* Hostname */
        for (;;) {
            if (*ptr == '/' || *ptr == ':' || *ptr == '#' || *ptr == '\0') {
                toklen = (size_t)(ptr - start);
                if (toklen == 0) {
                    http_set_error("empty host");
                    return -1;
                }

                uri->host = http_uri_decode_component(start, toklen);
                if (!uri->host)
                    return -1;

                break;
            }

            ptr++;
        }
    }

    /* Port (optional) */
    if (*ptr == ':') {
        ptr++;

        start = ptr;

        for (;;) {
            if (*ptr == '/' || *ptr == '#' || *ptr == '\0') {
                toklen = (size_t)(ptr - start);
                if (toklen == 0) {
                    http_set_error("empty port");
                    return -1;
                }

                uri->port = http_uri_decode_component(start, toklen);
                if (!uri->port)
                    return -1;

                break;
            } else if (!http_uri_is_port_char((unsigned char)*ptr)) {
                http_set_error("invalid character \\%hhu in port",
                               (unsigned char)*ptr);
                return -1;
            }

            ptr++;
        }
    }

    /* Path (optional, default '/') */
path:
    if (*ptr == '/') {
        start = ptr;

        for (;;) {
            if (*ptr == '?' || *ptr == '#' || *ptr == '\0') {
                toklen = (size_t)(ptr - start);
                uri->path = http_uri_decode_component(start, toklen);
                if (!uri->path)
                    return -1;

                break;
            }

            ptr++;
        }
    } else {
        uri->path = http_strdup("/");
    }

    /* Query (optional) */
    if (*ptr == '?') {
        char *query;

        ptr++;

        start = ptr;

        while (*ptr != '#' && *ptr != '\0')
            ptr++;

        toklen = (size_t)(ptr - start);
        query = http_strndup(start, toklen);

        if (http_query_parameters_parse(query,
                                        &uri->query_parameters,
                                        &uri->nb_query_parameters) == -1) {
            http_free(query);
            return -1;
        }

        http_free(query);
    }

    /* Fragment (optional) */
    if (*ptr == '#') {
        ptr++;

        start = ptr;

        while (*ptr != '\0')
            ptr++;

        toklen = (size_t)(ptr - start);
        uri->fragment = http_uri_decode_component(start, toklen);
        if (!uri->fragment)
            return -1;
    }

    if (http_uri_finalize(uri) == -1)
        return -1;

    return 1;
}
コード例 #12
0
ファイル: routes.c プロジェクト: lubing521/libhttp
int
http_route_base_find_route(struct http_route_base *base,
                           enum http_method method, const char *path,
                           const struct http_route **proute,
                           enum http_route_match_result *p_match_result,
                           struct http_named_parameter **p_named_parameters,
                           size_t *p_nb_named_parameters) {
    struct http_route *route;
    struct http_named_parameter *named_parameters;
    size_t nb_named_parameters;
    enum http_route_match_result match_result;
    char **path_components;
    size_t nb_path_components, idx;

    if (!base->sorted)
        http_route_base_sort_routes(base);

    if (*path != '/') {
        *proute = NULL;
        *p_match_result = HTTP_ROUTE_MATCH_WRONG_PATH;
        return 0;
    }

    if (http_path_parse(path, &path_components, &nb_path_components) == -1)
        return -1;

    route = NULL;
    match_result = HTTP_ROUTE_MATCH_PATH_NOT_FOUND;

    for (size_t i = 0; i < base->nb_routes; i++) {
        enum http_route_match_result result;

        if (http_route_matches_request(base->routes[i], method,
                                       path_components, nb_path_components,
                                       &result)) {
            route = base->routes[i];
            match_result = HTTP_ROUTE_MATCH_OK;
            break;
        }

        if (result == HTTP_ROUTE_MATCH_METHOD_NOT_FOUND) {
            match_result = HTTP_ROUTE_MATCH_METHOD_NOT_FOUND;
        } else if (result == HTTP_ROUTE_MATCH_PATH_NOT_FOUND
                && match_result != HTTP_ROUTE_MATCH_METHOD_NOT_FOUND) {
            match_result = HTTP_ROUTE_MATCH_PATH_NOT_FOUND;
        }
    }

    if (!route) {
        *proute = NULL;
        *p_match_result = match_result;

        http_path_free(path_components, nb_path_components);
        return 0;
    }

    if (route->nb_components != nb_path_components) {
        /* We made a mistake somewhere, it should not happen */
        http_set_error("route/path size mismatch");
        return -1;
    }

    /* Copy named parameters */
    nb_named_parameters = 0;
    for (size_t i = 0; i < route->nb_components; i++) {
        if (route->components[i].type == HTTP_ROUTE_COMPONENT_NAMED)
            nb_named_parameters++;
    }

    if (p_named_parameters && nb_named_parameters > 0) {
        named_parameters = http_calloc(nb_named_parameters,
                                       sizeof(struct http_named_parameter));

        idx = 0;
        for (size_t i = 0; i < route->nb_components; i++) {
            struct http_route_component *component;

            component = route->components + i;

            if (component->type != HTTP_ROUTE_COMPONENT_NAMED)
                continue;

            named_parameters[idx].name = http_strdup(component->value);
            named_parameters[idx].value = http_strdup(path_components[i]);
            idx++;
        }
    } else {
        named_parameters = NULL;
    }

    http_path_free(path_components, nb_path_components);

    *proute = route;
    *p_match_result = match_result;

    if (p_named_parameters)
        *p_named_parameters = named_parameters;
    if (p_nb_named_parameters)
        *p_nb_named_parameters = nb_named_parameters;
    return 0;
}
コード例 #13
0
ファイル: http.c プロジェクト: noelbk/bklib
int
http_header_parse(http_header_t *http, char *buf, size_t len) {
    char *ptr, *end=buf+len, *p, *q, *word=0;
    int is_space, is_nl;
    int line;
    char *line_ptr;
    http_keyval_t *hdr = 0;
    http_state_t state, state_next;
    
    http_header_clear(http);

    line = 0;
    line_ptr = buf;
    state = state_next = HTTP_STATE_INIT;

#define HTTP_HEADER_PARSE_ERROR \
	    http->error_state = state; \
	    http->error_line = line; \
	    http->error_col = ptr-line_ptr; \
	    state = HTTP_STATE_ERROR; \
	    break;

    for(ptr=buf; ptr<end && state!=HTTP_STATE_DONE && state!=HTTP_STATE_ERROR; ptr++) {
	/* ignore '\r' */
	if( *ptr == '\r' ) { 
	    continue; 
	}

	is_nl    = *ptr == '\n';
	is_space = *ptr == ' ' || *ptr == '\t';
	if( is_nl ) {
	    line++;
	    line_ptr = ptr;
	}


	/*
	  debug(DEBUG_INFO, 
	  ("http_header_parse: state=%d line=%d col=%d\n",
	  state, line, ptr-line_ptr));
	*/

	switch(state) {
	case HTTP_STATE_INIT: {
	    /* skip spaces and newlines */
	    if( !is_space && !is_nl ) {
		state = HTTP_STATE_OP;
		word = ptr;
		ptr--;
	    }
	    break;
	}

	case HTTP_STATE_SPACE: {
	    /* skip spaces, not newlines */
	    if( !is_space ) {
		state = state_next;
		word = ptr;
		ptr--;
	    }
	    break;
	}

	case HTTP_STATE_OP: {
	    if( is_nl ) { HTTP_HEADER_PARSE_ERROR; }
	    if( is_space ) {
		http->op = http_strdup(http, word, ptr-word);
		if( strncmp(http->op, "HTTP/", 5)==0 ) {
		    http->http_version = http->op;
		    http->op = 0;
		    http->op_code = HTTP_OP_RESPONSE;
		    state      = HTTP_STATE_SPACE; 
		    state_next = HTTP_STATE_RESPONSE_CODE;
		}
		else {
		    if( strcmp(http->op, "GET")==0 ) { 
			http->op_code = HTTP_OP_GET;
		    }
		    else if( strcmp(http->op, "PUT")==0 ) { 
			http->op_code = HTTP_OP_PUT;
		    }
		    else if( strcmp(http->op, "POST")==0 ) { 
			http->op_code = HTTP_OP_POST;
		    }
		    else {
			http->op_code = HTTP_OP_UNKNOWN;
		    }
		    state      = HTTP_STATE_SPACE; 
		    state_next = HTTP_STATE_URI;
		}
	    }
	    break;
	}

	case HTTP_STATE_RESPONSE_CODE: {
	    if( is_space || is_nl ) {
		http->response_code = strtoul(word, &q, 0);
		if( q<=word ) { HTTP_HEADER_PARSE_ERROR; }
		state      = HTTP_STATE_SPACE; 
		state_next = HTTP_STATE_RESPONSE_MESSAGE;
		if( is_nl ) { 
		    /* no message */
		    state  = HTTP_STATE_HEADER;
		}
	    }
	    break;
	}

	case HTTP_STATE_RESPONSE_MESSAGE: {
	    if( is_nl ) {
		http->response_message = http_strdup(http, word, ptr-word);
		state = HTTP_STATE_HEADER;
	    }
	    break;
	}
	
	case HTTP_STATE_URI: {
	    if( is_space || is_nl ) {
		http->uri = http_strdup(http, word, ptr-word);
		state = HTTP_STATE_SPACE; 
		state_next = HTTP_STATE_VERSION;
	    }
	    if( is_nl ) { 
		state_next = HTTP_STATE_HEADER;
	    }
	    break;
	}

	case HTTP_STATE_VERSION: {
	    if( is_space || is_nl ) {
		http->http_version = http_strdup(http, word, ptr-word);
		if( is_nl ) {
		    state = HTTP_STATE_HEADER;
		}
		else {
		    state = HTTP_STATE_SPACE; 
		    state_next = HTTP_STATE_HEADER_BOL;
		}

	    }
	    break;
	}

	case HTTP_STATE_HEADER_BOL: {
	    if( !is_nl ) { HTTP_HEADER_PARSE_ERROR; }
	    state = HTTP_STATE_HEADER;
	    break;
	}

	case HTTP_STATE_HEADER: {
	    if( is_space && !is_nl ) {
		/* add to previous header */
		state = HTTP_STATE_HEADER_VAL;
	    }
	    else {
		/* finish off the last header */
		if( http->headers_last ) {
		    http->headers_last->val = http_strdup(http, word, ptr-word);
		}
		
		if( is_nl ) {
		    /* done! */
		    state = HTTP_STATE_DONE;
		}
		else {
		    /* start new header */
		    hdr = pool_malloc(http->pool, sizeof(*hdr));
		    if( http->headers_last ) {
			http->headers_last->next = hdr;
		    }
		    else {
			http->headers = hdr;
		    }
		    http->headers_last = hdr;

		    word = ptr;
		    state = HTTP_STATE_HEADER_NAME;
		}
	    }
	    break;
	}

	case HTTP_STATE_HEADER_NAME: {
	    if( !(isalnum(*ptr) || *ptr == '-') ) {
		if( *ptr != ':' ) { HTTP_HEADER_PARSE_ERROR; }

		http->headers_last->key = http_strdup(http, word, ptr-word);
		state      = HTTP_STATE_SPACE; 
		state_next = HTTP_STATE_HEADER_VAL;
	    }
	    break;
	}

	case HTTP_STATE_HEADER_VAL: {
	    if( is_nl ) {
		state = HTTP_STATE_HEADER;
	    }
	    break;
	}

	case HTTP_STATE_DONE: {
	    break;
	}
	    
	default: break;
	}
    }

    if( state == HTTP_STATE_ERROR ) {
	return -http->error_state;
    }

    if( state != HTTP_STATE_DONE ) {
	http_header_clear(http);
	return 0;
    }

    http->header_len = ptr-buf;
    http->total_len  = http->header_len;

    /* done! for convenience, set up content length etc */
    http->content_ptr = ptr;
    p = http_keyval_get(http->headers, "content-length", 0);
    http->content_len = 0;
    if( p ) {
	http->content_len = strtoul(p, &q, 0);
	http->total_len  += http->content_len;
    }

    http->content_type = http_keyval_get(http->headers, "content-type", 0);

    return 1;
}