39 size_t inlen = strlen(s);
44 memset(&strm, 0,
sizeof(strm));
45 if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY) != Z_OK)
47 cap = deflateBound(&strm, (uLong)inlen);
53 strm.next_in = (Bytef*)s;
54 strm.avail_in = (uInt)inlen;
55 strm.next_out = (Bytef*)buf;
56 strm.avail_out = (uInt)cap;
57 deflate(&strm, Z_FINISH);
58 outlen = cap - strm.avail_out;
70 while ((opt = getopt(argc, argv,
"hvV:")) != EOF) {
73 if (!strncmp(
"LOG_NULL", optarg, 8))
75 else if (!strncmp(
"LOG_NOTICE", optarg, 10))
77 else if (!strncmp(
"LOG_INFO", optarg, 8))
79 else if (!strncmp(
"LOG_ERR", optarg, 7))
81 else if (!strncmp(
"LOG_DEBUG", optarg, 9))
84 fprintf(stderr,
"Unknown log level %s\n", optarg);
89 fprintf(stderr,
"ex_url\n");
93 fprintf(stderr,
"usage: %s [-V LOG_LEVEL]\n", argv[0]);
101 if (!got || !got->
data || strcmp(got->
data, want) != 0) {
102 n_log(
LOG_ERR,
"canon('%s'): got '%s', expected '%s'", in, got && got->
data ? got->
data :
"(null)", want);
112 if (!got || !got->
data || strcmp(got->
data, want) != 0) {
113 n_log(
LOG_ERR,
"resolve('%s','%s'): got '%s', expected '%s'", base, ref, got && got->
data ? got->
data :
"(null)", want);
121int main(
int argc,
char** argv) {
126 expect_canon(
"HTTP://Example.COM:80/a/./b/../c?x=1",
"http://example.com/a/c?x=1");
129 expect_canon(
"https://host/a/b/../../c/",
"https://host/c/");
131 expect_canon(
"http://host:8080/p",
"http://host:8080/p");
137 if (!a || !b || strcmp(a->
data, b->
data) != 0) {
147 const char* base =
"http://example.com/dir/page.html?old=1";
148 expect_resolve(base,
"other.html",
"http://example.com/dir/other.html");
149 expect_resolve(base,
"sub/leaf.html",
"http://example.com/dir/sub/leaf.html");
150 expect_resolve(base,
"/root.html",
"http://example.com/root.html");
152 expect_resolve(base,
"./same.html",
"http://example.com/dir/same.html");
153 expect_resolve(base,
"?new=2",
"http://example.com/dir/page.html?new=2");
154 expect_resolve(base,
"#frag",
"http://example.com/dir/page.html?old=1");
155 expect_resolve(base,
"next.html#frag",
"http://example.com/dir/next.html");
156 expect_resolve(base,
"//cdn.example.org/x.js",
"http://cdn.example.org/x.js");
157 expect_resolve(base,
"https://other.test/p",
"https://other.test/p");
159 expect_resolve(base,
"",
"http://example.com/dir/page.html?old=1");
162 expect_resolve(
"http://host:8080/a/b",
"c",
"http://host:8080/a/c");
181 const char* msg =
"The quick brown fox jumps over the lazy dog, repeatedly. AAAAAAAAAAAA.";
218 "Content-Disposition: form-data; name=\"field1\"\r\n"
222 "Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\"\r\n"
223 "Content-Type: text/plain\r\n"
230 if (
n_http_multipart_boundary(
"multipart/form-data; boundary=----WebKitX", bnd,
sizeof(bnd)) != 0 || strcmp(bnd,
"----WebKitX") != 0) {
231 n_log(
LOG_ERR,
"boundary extraction failed: '%s'", bnd);
234 if (!parts || parts->
nb_items != 2) {
235 n_log(
LOG_ERR,
"multipart parse: expected 2 parts, got %zu", parts ? parts->
nb_items : (size_t)0);
240 if (strcmp(p0->
name,
"field1") != 0 || strcmp(p0->
filename,
"") != 0 || !p0->
body || strcmp(p0->
body->
data,
"value1") != 0) {
244 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) {
252 if (!parts2 || parts2->
nb_items != 2) {
253 n_log(
LOG_ERR,
"multipart round-trip: expected 2 parts");
257 if (strcmp(q1->
name,
"file1") != 0 || strcmp(q1->
filename,
"a.txt") != 0 || strcmp(q1->
body->
data,
"file-content") != 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.
char * filename
Content-Disposition filename, or "".
char * content_type
the part's Content-Type, or ""
N_STR * body
the part's raw body bytes (binary-safe), or NULL
char * name
Content-Disposition form-field name, or "".
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.