n_url_canonicalize regression test (scheme/host case, default port, dot segments).
n_url_canonicalize regression test (scheme/host case, default port, dot segments).
#include <stdio.h>
#include <string.h>
#include <zlib.h>
z_stream strm;
size_t inlen = strlen(s);
uLong cap;
char* buf;
size_t outlen;
memset(&strm, 0, sizeof(strm));
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY) != Z_OK)
return NULL;
cap = deflateBound(&strm, (uLong)inlen);
buf = malloc(cap);
if (!buf) {
deflateEnd(&strm);
return NULL;
}
strm.next_in = (Bytef*)s;
strm.avail_in = (uInt)inlen;
strm.next_out = (Bytef*)buf;
strm.avail_out = (uInt)cap;
deflate(&strm, Z_FINISH);
outlen = cap - strm.avail_out;
deflateEnd(&strm);
free(buf);
return r;
}
int opt = 0;
while ((opt = getopt(argc, argv, "hvV:")) != EOF) {
switch (opt) {
case 'V':
if (!strncmp("LOG_NULL", optarg, 8))
else if (!strncmp("LOG_NOTICE", optarg, 10))
else if (!strncmp("LOG_INFO", optarg, 8))
else if (!strncmp("LOG_ERR", optarg, 7))
else if (!strncmp("LOG_DEBUG", optarg, 9))
else {
fprintf(stderr, "Unknown log level %s\n", optarg);
exit(1);
}
break;
case 'v':
fprintf(stderr, "ex_url\n");
exit(1);
case 'h':
default:
fprintf(stderr, "usage: %s [-V LOG_LEVEL]\n", argv[0]);
break;
}
}
}
static void expect_canon(
const char* in,
const char* want) {
if (!got || !got->
data || strcmp(got->
data, want) != 0) {
n_log(
LOG_ERR,
"canon('%s'): got '%s', expected '%s'", in, got && got->
data ? got->
data :
"(null)", want);
} else {
}
}
static void expect_resolve(
const char* base,
const char* ref,
const char* want) {
if (!got || !got->
data || strcmp(got->
data, want) != 0) {
n_log(
LOG_ERR,
"resolve('%s','%s'): got '%s', expected '%s'", base, ref, got && got->
data ? got->
data :
"(null)", want);
} else {
}
}
int main(
int argc,
char** argv) {
expect_canon(
"HTTP://Example.COM:80/a/./b/../c?x=1",
"http://example.com/a/c?x=1");
expect_canon(
"https://host/a/b/../../c/",
"https://host/c/");
{
if (!a || !b || strcmp(a->
data, b->
data) != 0) {
n_log(
LOG_ERR,
"dedup mismatch: '%s' vs '%s'", a && a->
data ? a->
data :
"(null)", b && b->data ? b->data :
"(null)");
}
}
{
const char* base = "http://example.com/dir/page.html?old=1";
expect_resolve(base,
"other.html",
"http://example.com/dir/other.html");
expect_resolve(base,
"sub/leaf.html",
"http://example.com/dir/sub/leaf.html");
expect_resolve(base,
"./same.html",
"http://example.com/dir/same.html");
expect_resolve(base,
"?new=2",
"http://example.com/dir/page.html?new=2");
expect_resolve(base,
"#frag",
"http://example.com/dir/page.html?old=1");
expect_resolve(base,
"next.html#frag",
"http://example.com/dir/next.html");
expect_resolve(base,
"//cdn.example.org/x.js",
"http://cdn.example.org/x.js");
}
{
}
}
{
const char* msg = "The quick brown fox jumps over the lazy dog, repeatedly. AAAAAAAAAAAA.";
} else {
}
} else {
}
} else {
}
}
{
char bnd[128];
const char* wire =
"--BkXyZ\r\n"
"Content-Disposition: form-data; name=\"field1\"\r\n"
"\r\n"
"value1\r\n"
"--BkXyZ\r\n"
"Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\"\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"file-content\r\n"
"--BkXyZ--\r\n";
if (
n_http_multipart_boundary(
"multipart/form-data; boundary=----WebKitX", bnd,
sizeof(bnd)) != 0 || strcmp(bnd,
"----WebKitX") != 0) {
}
} else {
if (strcmp(p0->name, "field1") != 0 || strcmp(p0->filename, "") != 0 || !p0->body || strcmp(p0->body->data, "value1") != 0) {
n_log(
LOG_ERR,
"multipart part0 wrong: name=%s file=%s body=%s", p0->name, p0->filename, p0->body ? p0->body->data :
"(null)");
}
if (strcmp(p1->name, "file1") != 0 || strcmp(p1->filename, "a.txt") != 0 || strcmp(p1->content_type, "text/plain") != 0 || !p1->body || strcmp(p1->body->data, "file-content") != 0) {
n_log(
LOG_ERR,
"multipart part1 wrong: name=%s file=%s ct=%s body=%s", p1->name, p1->filename, p1->content_type, p1->body ? p1->body->data :
"(null)");
}
{
} else {
if (strcmp(q1->name, "file1") != 0 || strcmp(q1->filename, "a.txt") != 0 || strcmp(q1->body->data, "file-content") != 0) {
}
}
}
}
}
return 1;
}
return 0;
}
void process_args(int argc, char **argv)
static void expect_canon(const char *in, const char *want)
static N_STR * gz_compress(const char *s, int window_bits)
static void expect_resolve(const char *base, const char *ref, const char *want)
void * ptr
void pointer to store
LIST_NODE * start
pointer to the start of the list
size_t nb_items
number of item currently in the list
struct LIST_NODE * next
pointer to the next node
Structure of a generic LIST container.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
#define LOG_NOTICE
normal but significant condition
#define LOG_NULL
no log output
#define LOG_INFO
informational
size_t NSTRBYTE
N_STR base unit.
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
int char_to_nstr_ex(const char *from, NSTRBYTE nboct, N_STR **to)
Convert a char into a N_STR, extended version.
A box including a string and his lenght.
N_STR * n_http_build_multipart(LIST *parts, const char *boundary)
build a multipart/form-data body from a LIST of N_HTTP_MULTIPART_PART* using boundary (without "--");...
int n_http_status_class(int status_code)
leading digit of an HTTP status code (1..5), or 0 when outside 100..599
void n_http_multipart_free(LIST **parts)
free a LIST returned by n_http_parse_multipart and NULL the pointer
N_STR * n_url_canonicalize_string(const char *url)
parse and canonicalize a URL string in one call
N_STR * n_url_resolve(const char *base, const char *ref)
resolve a (possibly relative) URL reference against an absolute base
int n_http_status_is_server_error(int status_code)
1 when status_code is a server error (5xx), else 0
int n_http_status_is_client_error(int status_code)
1 when status_code is a client error (4xx), else 0
int n_http_decompress_body(const N_STR *body, const char *encoding, N_STR **out)
decompress an HTTP body per its Content-Encoding ("gzip"/"deflate"; identity/NULL/unknown copies thro...
int n_http_multipart_boundary(const char *content_type, char *out, size_t outsz)
copy the boundary token from a Content-Type value into out (without the leading "--").
int n_http_status_is_informational(int status_code)
1 when status_code is informational (1xx), else 0
int n_http_status_is_success(int status_code)
1 when status_code is success (2xx), else 0
int n_http_status_is_redirect(int status_code)
1 when status_code is a redirect (3xx), else 0
LIST * n_http_parse_multipart(const N_STR *body, const char *boundary)
parse a multipart body (boundary given without "--") into a LIST of N_HTTP_MULTIPART_PART*; free with...
a single part of a parsed multipart/form-data body
Common headers and low-level functions & define.
N_STR and string function declaration.