/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "strfuncs.h"
#include "net.h"
#include "uri-util.h"
#include "http-url.h"
#include "http-request.h"
/*
* HTTP URL parser
*/
struct http_url_parser {
};
{
int ret;
return FALSE;
/* RFC 7230, Section 2.7.1: http URI Scheme
A sender MUST NOT generate an "http" URI with an empty host
identifier. A recipient that processes such a URI reference MUST
reject it as invalid.
*/
return FALSE;
}
if (ret > 0) {
const char *p;
/* RFC 7230, Section 2.7.1: http URI Scheme
A sender MUST NOT generate the userinfo subcomponent (and its "@"
delimiter) when an "http" URI reference is generated within a
message as a request target or header field value. Before making
use of an "http" URI reference received from an untrusted source,
a recipient SHOULD parse for userinfo and treat its presence as
an error; it is likely being used to obscure the authority for
the sake of phishing attacks.
*/
return FALSE;
}
if (p == NULL) {
return FALSE;
} else {
return FALSE;
return FALSE;
}
}
}
}
return TRUE;
}
{
return FALSE;
return FALSE;
return TRUE;
}
{
const char *const *path;
int path_relative;
const char *part;
int ret;
/* RFC 7230, Appendix B:
http-URI = "http://" authority path-abempty [ "?" query ]
[ "#" fragment ]
https-URI = "https://" authority path-abempty [ "?" query ]
[ "#" fragment ]
partial-URI = relative-part [ "?" query ]
request-target = origin-form / absolute-form / authority-form /
asterisk-form
origin-form = absolute-path [ "?" query ]
absolute-form = absolute-URI
authority-form = authority
asterisk-form = "*"
; Not parsed here
absolute-path = 1*( "/" segment )
RFC 3986, Appendix A: (implemented in uri-util.h)
absolute-URI = scheme ":" hier-part [ "?" query ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
relative-part = "//" authority path-abempty
/ path-absolute
/ path-noscheme
/ path-empty
authority = [ userinfo "@" ] host [ ":" port ]
path-abempty = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )
path-empty = 0<pchar>
segment = *pchar
segment-nz = 1*pchar
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
; non-zero-length segment without any colon ":"
query = *( pchar / "/" / "?" )
fragment = *( pchar / "/" / "?" )
*/
/* "http:" / "https:" */
const char *scheme;
} else {
if (url_parser->request_target) {
/* valid as non-HTTP scheme, but also try to parse as authority */
if (!http_url_parse_authority_form(url_parser)) {
}
return TRUE;
}
return FALSE;
}
have_scheme = TRUE;
}
} else {
have_scheme = TRUE;
}
/* "//" authority ; or
* ["//"] authority ; when parsing a request target
*/
} else {
/* start of absolute-path */
}
if (!http_url_parse_authority_form(url_parser)) {
/* not non-HTTP scheme and invalid as authority-form */
return FALSE;
}
return TRUE;
}
if (have_scheme && !have_authority) {
return FALSE;
}
if (have_authority) {
return FALSE;
}
/* path-abempty / path-absolute / path-noscheme / path-empty */
return FALSE;
/* Relative URLs are only valid when we have a base URL */
if (relative) {
return FALSE;
}
}
/* Resolve path */
if (ret > 0) {
const char *p = pend - 1;
/* discard trailing segments of base path based on how many effective
leading '..' segments were found in the relative path.
*/
while (path_relative > 0 && p > pbegin) {
while (p > pbegin && *p != '/') p--;
if (p >= pbegin) {
pend = p;
}
if (p > pbegin) p--;
}
}
/* append relative path */
return FALSE;
}
path++;
}
}
/* [ "?" query ] */
return FALSE;
if (ret > 0) {
}
/* [ "#" fragment ] */
return FALSE;
if (ret > 0) {
return FALSE;
}
}
/* must be at end of URL now */
if (have_scheme)
return TRUE;
}
/* Public API */
{
/* base != NULL indicates whether relative URLs are allowed. However, certain
i_zero(&url_parser);
if (!http_url_do_parse(&url_parser)) {
return -1;
}
return 0;
}
const char **error_r)
{
i_zero(&url_parser);
return -1;
}
*error_r = "Invalid Host header: Contains invalid character";
return -1;
}
return 0;
}
url_parser.flags = 0;
if (!http_url_do_parse(&url_parser)) {
return -1;
}
return 0;
}
/*
* HTTP URL manipulation
*/
{
}
{
return new_url;
}
{
}
{
}
{
return new_url;
}
{
return new_url;
}
/*
* HTTP URL construction
*/
static void
{
/* scheme */
else
}
static void
{
/* host */
/* port */
}
static void
{
/* Older syntax of RFC 2616 requires this slash at all times for an
absolute URL
*/
} else {
}
/* query (pre-encoded) */
}
}
{
/* fragment */
}
}
{
}
{
}
{
}
{
}
{
}