Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.21)
project(http_client_c C)

set(CMAKE_C_STANDARD 11)
add_compile_options(-fms-extensions)

include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/encoding)

#file(GLOB SOURCES
# ${SOURCES}/src/encoding/*
# )

add_executable(http_client_c
${CMAKE_SOURCE_DIR}/test/main.c
)

#add_executable(http_chunked_c
# ${CMAKE_SOURCE_DIR}/test/chunked.c
# )


target_link_libraries(http_client_c m)
#target_link_libraries(http_chunked_c m)
File renamed without changes.
311 changes: 226 additions & 85 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,98 +10,239 @@ in C, it can be used in C++ code as well.

Basic Usage
===============
http_response

```c
#include "http/client.h"

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
// add an HTTP header, replace existing
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
// add an HTTP header, keep existing
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

// execute the request
http_response *response = http_request_exec(request);

http_request_free(request);
http_response_free(response);
```

## http_request

the request structure.

```c

typedef struct http_request {
http_header *headers;
size_t body_len;
char *body;
char *request_uri;
int max_redirect;
char *method;
http_header_cb_ptr *request_header_cb;
http_header_cb_ptr *response_header_cb;
http_response_body_cb_ptr *response_body_cb;
struct timeval *request_timeout;
} http_request;

```

## create a request struct pointer.

```c
http_request *request = http_request_new();
```

## configure the request options

```c

// http_request *hreq - the request struct pointer
// http_option option - the option to configure
// const void *val - option payload
// size_t len - the payload length, only needed if the payload is a binary string, otherwise pass 0
// void http_request_option(http_request *hreq, http_option option, const void *val, size_t len)


http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");
```

### http option flags
- HTTP_OPTION_URL: pass the url
- HTTP_OPTION_HEADER: pass an HTTP header as a _struct http_header_ pointer
- HTTP_OPTION_BODY: pass the request payload
- HTTP_OPTION_METHOD: pass the HTTP method
- HTTP_OPTION_REQUEST_TIMEOUT: set the request timeout as a numeric string
- HTTP_OPTION_REQUEST_HEADER_CALLBACK: pass a request header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_HEADER_CALLBACK: pass a response header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_BODY_CALLBACK: pass a response body callback (see ./test/main.c for an example)

http_response
-------------
http_response is a structure that is returned by all http_* methods, it contains information about the requse and the response.
Please note that all functions return a pointer to an insance of http_response. The structure is as following:

struct http_response
{
struct parsed_url *request_uri;
char *body;
char *status_code;
int status_code_int;
char *status_text;
char *request_headers;
char *response_headers;
};

#####*request_uri
This is an instance of the parsed_url structure, this contains the request URL and all information about the request
URL. Look up parsed_url for more information.

#####*body
This contains the response BODY (usually HTML).

#####*status_code
This contains the HTTP Status code returned by the server in plain text format.

#####status_code_int
This returns the same as status_code but as an integer.

#####*status_text
http_response is a structure that is returned by _http_request_exec_ method, it contains information about the response.
Please note that this function returns a pointer to an instance of http_response. The structure is as following:

```c

typedef struct http_response {
http_header *headers;
char *body;
size_t body_len;
char *redirect_uri;
int redirect_count;
int status_code;
char *status_text;
} http_response;
```

##### *redirect_ui
The last redirected url.

##### *redirect_count
the HTTP redirect count

##### *body
The response body. always NULL if you set a response body callback

##### body_len
the response body length

##### status_code
the response HTTP status code

##### *status_text
This returns the text associated with the status code. For status code 200, OK will be returned.

#####*request_headers
This contains the HTTP headers that were used to make the request.
##### *headers
response HTTP headers as _struct http_header_ pointer.

#####*response_headers
Contains the HTTP headers returned by the server.
## HTTP response callback

http_req()
-------------
http_req is the basis for all other http_* methodes and makes and HTTP request and returns an instance of the http_response structure.
Provide an HTTP response body callback to handle large HTTP response payload efficiently.
this will avoid allocating memory to hold the response.

The prototype for this function is:
## full example

struct http_response* http_req(char *http_headers, struct parsed_url *purl)

A simple example is:

struct parsed_url *purl = parse_url("http://www.google.com/");
struct http_response *hrep = http_req("GET / HTTP/1.1\r\nHostname:www.google.com\r\nConnection:close\r\n\r\n", purl);
```c

Please note that http_req does not handle redirects. (Status code 300-399)
#include "http/client.h"

http_get()
-------------
Makes an HTTP GET request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers.

The prototype for this function is:

struct http_response* http_get(char *url, char *custom_headers)

A simple example is:

struct http_response *hresp = http_get("http://www.google.com", "User-agent:MyUserAgent\r\n");

http_get does handle redirects automaticly. The basic headers used in this method:

GET / HTTP/1.1
Hostname:www.google.com
Connection:close

http_post
------------
Makes an HTTP POST request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers. In the third parameter
the post data can be specified.

The prototype for this function is:

struct http_response* http_post(char *url, char *custom_headers, char *post_data)

A simple example is:

struct http_response *hresp = http_post("http://mywebsite.com/login.php", "User-agent:MyuserAgent\r\n", "username=Kirk&password=lol123");

http_post does handle redirects automaticly. The basic headers used in this method:

POST /login.php HTTP/1.1
Hostname:mywebsite.com
Connection:close

username=Kirk&password=lol123

FILE *fp;

/**
* response header callback
* @param headers
*/
void response_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers received:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* request header callback
* @param headers
*/
void request_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers sent:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* response body callback
* @param chunk
* @param chunk_len
* @param headers
*/
void response_body_cb(const char *chunk, size_t chunk_len, http_header *headers) {

if (chunk_len > 0) {

fwrite(chunk, 1, chunk_len, fp);

http_header *content_type = http_header_get(headers, "Content-Type");

// if text content, dump to stderr
if (content_type != NULL && strstr(content_type->value, "text/") != NULL) {

fwrite(chunk, chunk_len, 1, stderr);
}

http_header_free(content_type);
}
}

int main(int argc, char *argv[]) {

if (argc <= 2) {

fprintf(stderr, "Usage: \n$ %s URL DEST_FILE\n", argv[0]);
exit(1);
}

char *filename = argc > 2 ? argv[2] : "";
fprintf(stderr, "opening %s ...\n", filename);

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firevox");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

fp = fopen(filename, "wb");

http_response *response = http_request_exec(request);

fclose(fp);

http_request_free(request);
http_response_free(response);

return 0;
}
```
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
enable safe binary data transfer and fixed memory leaks by tbela99 · Pull Request #2 · langhai/http-client-c · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.21)
project(http_client_c C)

set(CMAKE_C_STANDARD 11)
add_compile_options(-fms-extensions)

include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/encoding)

#file(GLOB SOURCES
# ${SOURCES}/src/encoding/*
# )

add_executable(http_client_c
${CMAKE_SOURCE_DIR}/test/main.c
)

#add_executable(http_chunked_c
# ${CMAKE_SOURCE_DIR}/test/chunked.c
# )


target_link_libraries(http_client_c m)
#target_link_libraries(http_chunked_c m)
File renamed without changes.
311 changes: 226 additions & 85 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,98 +10,239 @@ in C, it can be used in C++ code as well.

Basic Usage
===============
http_response

```c
#include "http/client.h"

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
// add an HTTP header, replace existing
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
// add an HTTP header, keep existing
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

// execute the request
http_response *response = http_request_exec(request);

http_request_free(request);
http_response_free(response);
```

## http_request

the request structure.

```c

typedef struct http_request {
http_header *headers;
size_t body_len;
char *body;
char *request_uri;
int max_redirect;
char *method;
http_header_cb_ptr *request_header_cb;
http_header_cb_ptr *response_header_cb;
http_response_body_cb_ptr *response_body_cb;
struct timeval *request_timeout;
} http_request;

```

## create a request struct pointer.

```c
http_request *request = http_request_new();
```

## configure the request options

```c

// http_request *hreq - the request struct pointer
// http_option option - the option to configure
// const void *val - option payload
// size_t len - the payload length, only needed if the payload is a binary string, otherwise pass 0
// void http_request_option(http_request *hreq, http_option option, const void *val, size_t len)


http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");
```

### http option flags
- HTTP_OPTION_URL: pass the url
- HTTP_OPTION_HEADER: pass an HTTP header as a _struct http_header_ pointer
- HTTP_OPTION_BODY: pass the request payload
- HTTP_OPTION_METHOD: pass the HTTP method
- HTTP_OPTION_REQUEST_TIMEOUT: set the request timeout as a numeric string
- HTTP_OPTION_REQUEST_HEADER_CALLBACK: pass a request header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_HEADER_CALLBACK: pass a response header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_BODY_CALLBACK: pass a response body callback (see ./test/main.c for an example)

http_response
-------------
http_response is a structure that is returned by all http_* methods, it contains information about the requse and the response.
Please note that all functions return a pointer to an insance of http_response. The structure is as following:

struct http_response
{
struct parsed_url *request_uri;
char *body;
char *status_code;
int status_code_int;
char *status_text;
char *request_headers;
char *response_headers;
};

#####*request_uri
This is an instance of the parsed_url structure, this contains the request URL and all information about the request
URL. Look up parsed_url for more information.

#####*body
This contains the response BODY (usually HTML).

#####*status_code
This contains the HTTP Status code returned by the server in plain text format.

#####status_code_int
This returns the same as status_code but as an integer.

#####*status_text
http_response is a structure that is returned by _http_request_exec_ method, it contains information about the response.
Please note that this function returns a pointer to an instance of http_response. The structure is as following:

```c

typedef struct http_response {
http_header *headers;
char *body;
size_t body_len;
char *redirect_uri;
int redirect_count;
int status_code;
char *status_text;
} http_response;
```

##### *redirect_ui
The last redirected url.

##### *redirect_count
the HTTP redirect count

##### *body
The response body. always NULL if you set a response body callback

##### body_len
the response body length

##### status_code
the response HTTP status code

##### *status_text
This returns the text associated with the status code. For status code 200, OK will be returned.

#####*request_headers
This contains the HTTP headers that were used to make the request.
##### *headers
response HTTP headers as _struct http_header_ pointer.

#####*response_headers
Contains the HTTP headers returned by the server.
## HTTP response callback

http_req()
-------------
http_req is the basis for all other http_* methodes and makes and HTTP request and returns an instance of the http_response structure.
Provide an HTTP response body callback to handle large HTTP response payload efficiently.
this will avoid allocating memory to hold the response.

The prototype for this function is:
## full example

struct http_response* http_req(char *http_headers, struct parsed_url *purl)

A simple example is:

struct parsed_url *purl = parse_url("http://www.google.com/");
struct http_response *hrep = http_req("GET / HTTP/1.1\r\nHostname:www.google.com\r\nConnection:close\r\n\r\n", purl);
```c

Please note that http_req does not handle redirects. (Status code 300-399)
#include "http/client.h"

http_get()
-------------
Makes an HTTP GET request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers.

The prototype for this function is:

struct http_response* http_get(char *url, char *custom_headers)

A simple example is:

struct http_response *hresp = http_get("http://www.google.com", "User-agent:MyUserAgent\r\n");

http_get does handle redirects automaticly. The basic headers used in this method:

GET / HTTP/1.1
Hostname:www.google.com
Connection:close

http_post
------------
Makes an HTTP POST request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers. In the third parameter
the post data can be specified.

The prototype for this function is:

struct http_response* http_post(char *url, char *custom_headers, char *post_data)

A simple example is:

struct http_response *hresp = http_post("http://mywebsite.com/login.php", "User-agent:MyuserAgent\r\n", "username=Kirk&password=lol123");

http_post does handle redirects automaticly. The basic headers used in this method:

POST /login.php HTTP/1.1
Hostname:mywebsite.com
Connection:close

username=Kirk&password=lol123

FILE *fp;

/**
* response header callback
* @param headers
*/
void response_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers received:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* request header callback
* @param headers
*/
void request_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers sent:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* response body callback
* @param chunk
* @param chunk_len
* @param headers
*/
void response_body_cb(const char *chunk, size_t chunk_len, http_header *headers) {

if (chunk_len > 0) {

fwrite(chunk, 1, chunk_len, fp);

http_header *content_type = http_header_get(headers, "Content-Type");

// if text content, dump to stderr
if (content_type != NULL && strstr(content_type->value, "text/") != NULL) {

fwrite(chunk, chunk_len, 1, stderr);
}

http_header_free(content_type);
}
}

int main(int argc, char *argv[]) {

if (argc <= 2) {

fprintf(stderr, "Usage: \n$ %s URL DEST_FILE\n", argv[0]);
exit(1);
}

char *filename = argc > 2 ? argv[2] : "";
fprintf(stderr, "opening %s ...\n", filename);

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firevox");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

fp = fopen(filename, "wb");

http_response *response = http_request_exec(request);

fclose(fp);

http_request_free(request);
http_response_free(response);

return 0;
}
```
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' enable safe binary data transfer and fixed memory leaks by tbela99 · Pull Request #2 · langhai/http-client-c · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.21)
project(http_client_c C)

set(CMAKE_C_STANDARD 11)
add_compile_options(-fms-extensions)

include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/encoding)

#file(GLOB SOURCES
# ${SOURCES}/src/encoding/*
# )

add_executable(http_client_c
${CMAKE_SOURCE_DIR}/test/main.c
)

#add_executable(http_chunked_c
# ${CMAKE_SOURCE_DIR}/test/chunked.c
# )


target_link_libraries(http_client_c m)
#target_link_libraries(http_chunked_c m)
File renamed without changes.
311 changes: 226 additions & 85 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,98 +10,239 @@ in C, it can be used in C++ code as well.

Basic Usage
===============
http_response

```c
#include "http/client.h"

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
// add an HTTP header, replace existing
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
// add an HTTP header, keep existing
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

// execute the request
http_response *response = http_request_exec(request);

http_request_free(request);
http_response_free(response);
```

## http_request

the request structure.

```c

typedef struct http_request {
http_header *headers;
size_t body_len;
char *body;
char *request_uri;
int max_redirect;
char *method;
http_header_cb_ptr *request_header_cb;
http_header_cb_ptr *response_header_cb;
http_response_body_cb_ptr *response_body_cb;
struct timeval *request_timeout;
} http_request;

```

## create a request struct pointer.

```c
http_request *request = http_request_new();
```

## configure the request options

```c

// http_request *hreq - the request struct pointer
// http_option option - the option to configure
// const void *val - option payload
// size_t len - the payload length, only needed if the payload is a binary string, otherwise pass 0
// void http_request_option(http_request *hreq, http_option option, const void *val, size_t len)


http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");
```

### http option flags
- HTTP_OPTION_URL: pass the url
- HTTP_OPTION_HEADER: pass an HTTP header as a _struct http_header_ pointer
- HTTP_OPTION_BODY: pass the request payload
- HTTP_OPTION_METHOD: pass the HTTP method
- HTTP_OPTION_REQUEST_TIMEOUT: set the request timeout as a numeric string
- HTTP_OPTION_REQUEST_HEADER_CALLBACK: pass a request header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_HEADER_CALLBACK: pass a response header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_BODY_CALLBACK: pass a response body callback (see ./test/main.c for an example)

http_response
-------------
http_response is a structure that is returned by all http_* methods, it contains information about the requse and the response.
Please note that all functions return a pointer to an insance of http_response. The structure is as following:

struct http_response
{
struct parsed_url *request_uri;
char *body;
char *status_code;
int status_code_int;
char *status_text;
char *request_headers;
char *response_headers;
};

#####*request_uri
This is an instance of the parsed_url structure, this contains the request URL and all information about the request
URL. Look up parsed_url for more information.

#####*body
This contains the response BODY (usually HTML).

#####*status_code
This contains the HTTP Status code returned by the server in plain text format.

#####status_code_int
This returns the same as status_code but as an integer.

#####*status_text
http_response is a structure that is returned by _http_request_exec_ method, it contains information about the response.
Please note that this function returns a pointer to an instance of http_response. The structure is as following:

```c

typedef struct http_response {
http_header *headers;
char *body;
size_t body_len;
char *redirect_uri;
int redirect_count;
int status_code;
char *status_text;
} http_response;
```

##### *redirect_ui
The last redirected url.

##### *redirect_count
the HTTP redirect count

##### *body
The response body. always NULL if you set a response body callback

##### body_len
the response body length

##### status_code
the response HTTP status code

##### *status_text
This returns the text associated with the status code. For status code 200, OK will be returned.

#####*request_headers
This contains the HTTP headers that were used to make the request.
##### *headers
response HTTP headers as _struct http_header_ pointer.

#####*response_headers
Contains the HTTP headers returned by the server.
## HTTP response callback

http_req()
-------------
http_req is the basis for all other http_* methodes and makes and HTTP request and returns an instance of the http_response structure.
Provide an HTTP response body callback to handle large HTTP response payload efficiently.
this will avoid allocating memory to hold the response.

The prototype for this function is:
## full example

struct http_response* http_req(char *http_headers, struct parsed_url *purl)

A simple example is:

struct parsed_url *purl = parse_url("http://www.google.com/");
struct http_response *hrep = http_req("GET / HTTP/1.1\r\nHostname:www.google.com\r\nConnection:close\r\n\r\n", purl);
```c

Please note that http_req does not handle redirects. (Status code 300-399)
#include "http/client.h"

http_get()
-------------
Makes an HTTP GET request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers.

The prototype for this function is:

struct http_response* http_get(char *url, char *custom_headers)

A simple example is:

struct http_response *hresp = http_get("http://www.google.com", "User-agent:MyUserAgent\r\n");

http_get does handle redirects automaticly. The basic headers used in this method:

GET / HTTP/1.1
Hostname:www.google.com
Connection:close

http_post
------------
Makes an HTTP POST request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers. In the third parameter
the post data can be specified.

The prototype for this function is:

struct http_response* http_post(char *url, char *custom_headers, char *post_data)

A simple example is:

struct http_response *hresp = http_post("http://mywebsite.com/login.php", "User-agent:MyuserAgent\r\n", "username=Kirk&password=lol123");

http_post does handle redirects automaticly. The basic headers used in this method:

POST /login.php HTTP/1.1
Hostname:mywebsite.com
Connection:close

username=Kirk&password=lol123

FILE *fp;

/**
* response header callback
* @param headers
*/
void response_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers received:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* request header callback
* @param headers
*/
void request_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers sent:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* response body callback
* @param chunk
* @param chunk_len
* @param headers
*/
void response_body_cb(const char *chunk, size_t chunk_len, http_header *headers) {

if (chunk_len > 0) {

fwrite(chunk, 1, chunk_len, fp);

http_header *content_type = http_header_get(headers, "Content-Type");

// if text content, dump to stderr
if (content_type != NULL && strstr(content_type->value, "text/") != NULL) {

fwrite(chunk, chunk_len, 1, stderr);
}

http_header_free(content_type);
}
}

int main(int argc, char *argv[]) {

if (argc <= 2) {

fprintf(stderr, "Usage: \n$ %s URL DEST_FILE\n", argv[0]);
exit(1);
}

char *filename = argc > 2 ? argv[2] : "";
fprintf(stderr, "opening %s ...\n", filename);

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firevox");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

fp = fopen(filename, "wb");

http_response *response = http_request_exec(request);

fclose(fp);

http_request_free(request);
http_response_free(response);

return 0;
}
```
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' enable safe binary data transfer and fixed memory leaks by tbela99 · Pull Request #2 · langhai/http-client-c · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.21)
project(http_client_c C)

set(CMAKE_C_STANDARD 11)
add_compile_options(-fms-extensions)

include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/encoding)

#file(GLOB SOURCES
# ${SOURCES}/src/encoding/*
# )

add_executable(http_client_c
${CMAKE_SOURCE_DIR}/test/main.c
)

#add_executable(http_chunked_c
# ${CMAKE_SOURCE_DIR}/test/chunked.c
# )


target_link_libraries(http_client_c m)
#target_link_libraries(http_chunked_c m)
File renamed without changes.
311 changes: 226 additions & 85 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,98 +10,239 @@ in C, it can be used in C++ code as well.

Basic Usage
===============
http_response

```c
#include "http/client.h"

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
// add an HTTP header, replace existing
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
// add an HTTP header, keep existing
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

// execute the request
http_response *response = http_request_exec(request);

http_request_free(request);
http_response_free(response);
```

## http_request

the request structure.

```c

typedef struct http_request {
http_header *headers;
size_t body_len;
char *body;
char *request_uri;
int max_redirect;
char *method;
http_header_cb_ptr *request_header_cb;
http_header_cb_ptr *response_header_cb;
http_response_body_cb_ptr *response_body_cb;
struct timeval *request_timeout;
} http_request;

```

## create a request struct pointer.

```c
http_request *request = http_request_new();
```

## configure the request options

```c

// http_request *hreq - the request struct pointer
// http_option option - the option to configure
// const void *val - option payload
// size_t len - the payload length, only needed if the payload is a binary string, otherwise pass 0
// void http_request_option(http_request *hreq, http_option option, const void *val, size_t len)


http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");
```

### http option flags
- HTTP_OPTION_URL: pass the url
- HTTP_OPTION_HEADER: pass an HTTP header as a _struct http_header_ pointer
- HTTP_OPTION_BODY: pass the request payload
- HTTP_OPTION_METHOD: pass the HTTP method
- HTTP_OPTION_REQUEST_TIMEOUT: set the request timeout as a numeric string
- HTTP_OPTION_REQUEST_HEADER_CALLBACK: pass a request header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_HEADER_CALLBACK: pass a response header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_BODY_CALLBACK: pass a response body callback (see ./test/main.c for an example)

http_response
-------------
http_response is a structure that is returned by all http_* methods, it contains information about the requse and the response.
Please note that all functions return a pointer to an insance of http_response. The structure is as following:

struct http_response
{
struct parsed_url *request_uri;
char *body;
char *status_code;
int status_code_int;
char *status_text;
char *request_headers;
char *response_headers;
};

#####*request_uri
This is an instance of the parsed_url structure, this contains the request URL and all information about the request
URL. Look up parsed_url for more information.

#####*body
This contains the response BODY (usually HTML).

#####*status_code
This contains the HTTP Status code returned by the server in plain text format.

#####status_code_int
This returns the same as status_code but as an integer.

#####*status_text
http_response is a structure that is returned by _http_request_exec_ method, it contains information about the response.
Please note that this function returns a pointer to an instance of http_response. The structure is as following:

```c

typedef struct http_response {
http_header *headers;
char *body;
size_t body_len;
char *redirect_uri;
int redirect_count;
int status_code;
char *status_text;
} http_response;
```

##### *redirect_ui
The last redirected url.

##### *redirect_count
the HTTP redirect count

##### *body
The response body. always NULL if you set a response body callback

##### body_len
the response body length

##### status_code
the response HTTP status code

##### *status_text
This returns the text associated with the status code. For status code 200, OK will be returned.

#####*request_headers
This contains the HTTP headers that were used to make the request.
##### *headers
response HTTP headers as _struct http_header_ pointer.

#####*response_headers
Contains the HTTP headers returned by the server.
## HTTP response callback

http_req()
-------------
http_req is the basis for all other http_* methodes and makes and HTTP request and returns an instance of the http_response structure.
Provide an HTTP response body callback to handle large HTTP response payload efficiently.
this will avoid allocating memory to hold the response.

The prototype for this function is:
## full example

struct http_response* http_req(char *http_headers, struct parsed_url *purl)

A simple example is:

struct parsed_url *purl = parse_url("http://www.google.com/");
struct http_response *hrep = http_req("GET / HTTP/1.1\r\nHostname:www.google.com\r\nConnection:close\r\n\r\n", purl);
```c

Please note that http_req does not handle redirects. (Status code 300-399)
#include "http/client.h"

http_get()
-------------
Makes an HTTP GET request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers.

The prototype for this function is:

struct http_response* http_get(char *url, char *custom_headers)

A simple example is:

struct http_response *hresp = http_get("http://www.google.com", "User-agent:MyUserAgent\r\n");

http_get does handle redirects automaticly. The basic headers used in this method:

GET / HTTP/1.1
Hostname:www.google.com
Connection:close

http_post
------------
Makes an HTTP POST request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers. In the third parameter
the post data can be specified.

The prototype for this function is:

struct http_response* http_post(char *url, char *custom_headers, char *post_data)

A simple example is:

struct http_response *hresp = http_post("http://mywebsite.com/login.php", "User-agent:MyuserAgent\r\n", "username=Kirk&password=lol123");

http_post does handle redirects automaticly. The basic headers used in this method:

POST /login.php HTTP/1.1
Hostname:mywebsite.com
Connection:close

username=Kirk&password=lol123

FILE *fp;

/**
* response header callback
* @param headers
*/
void response_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers received:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* request header callback
* @param headers
*/
void request_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers sent:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* response body callback
* @param chunk
* @param chunk_len
* @param headers
*/
void response_body_cb(const char *chunk, size_t chunk_len, http_header *headers) {

if (chunk_len > 0) {

fwrite(chunk, 1, chunk_len, fp);

http_header *content_type = http_header_get(headers, "Content-Type");

// if text content, dump to stderr
if (content_type != NULL && strstr(content_type->value, "text/") != NULL) {

fwrite(chunk, chunk_len, 1, stderr);
}

http_header_free(content_type);
}
}

int main(int argc, char *argv[]) {

if (argc <= 2) {

fprintf(stderr, "Usage: \n$ %s URL DEST_FILE\n", argv[0]);
exit(1);
}

char *filename = argc > 2 ? argv[2] : "";
fprintf(stderr, "opening %s ...\n", filename);

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firevox");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

fp = fopen(filename, "wb");

http_response *response = http_request_exec(request);

fclose(fp);

http_request_free(request);
http_response_free(response);

return 0;
}
```
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' enable safe binary data transfer and fixed memory leaks by tbela99 · Pull Request #2 · langhai/http-client-c · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.21)
project(http_client_c C)

set(CMAKE_C_STANDARD 11)
add_compile_options(-fms-extensions)

include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/encoding)

#file(GLOB SOURCES
# ${SOURCES}/src/encoding/*
# )

add_executable(http_client_c
${CMAKE_SOURCE_DIR}/test/main.c
)

#add_executable(http_chunked_c
# ${CMAKE_SOURCE_DIR}/test/chunked.c
# )


target_link_libraries(http_client_c m)
#target_link_libraries(http_chunked_c m)
File renamed without changes.
311 changes: 226 additions & 85 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,98 +10,239 @@ in C, it can be used in C++ code as well.

Basic Usage
===============
http_response

```c
#include "http/client.h"

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
// add an HTTP header, replace existing
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
// add an HTTP header, keep existing
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

// execute the request
http_response *response = http_request_exec(request);

http_request_free(request);
http_response_free(response);
```

## http_request

the request structure.

```c

typedef struct http_request {
http_header *headers;
size_t body_len;
char *body;
char *request_uri;
int max_redirect;
char *method;
http_header_cb_ptr *request_header_cb;
http_header_cb_ptr *response_header_cb;
http_response_body_cb_ptr *response_body_cb;
struct timeval *request_timeout;
} http_request;

```

## create a request struct pointer.

```c
http_request *request = http_request_new();
```

## configure the request options

```c

// http_request *hreq - the request struct pointer
// http_option option - the option to configure
// const void *val - option payload
// size_t len - the payload length, only needed if the payload is a binary string, otherwise pass 0
// void http_request_option(http_request *hreq, http_option option, const void *val, size_t len)


http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");
```

### http option flags
- HTTP_OPTION_URL: pass the url
- HTTP_OPTION_HEADER: pass an HTTP header as a _struct http_header_ pointer
- HTTP_OPTION_BODY: pass the request payload
- HTTP_OPTION_METHOD: pass the HTTP method
- HTTP_OPTION_REQUEST_TIMEOUT: set the request timeout as a numeric string
- HTTP_OPTION_REQUEST_HEADER_CALLBACK: pass a request header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_HEADER_CALLBACK: pass a response header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_BODY_CALLBACK: pass a response body callback (see ./test/main.c for an example)

http_response
-------------
http_response is a structure that is returned by all http_* methods, it contains information about the requse and the response.
Please note that all functions return a pointer to an insance of http_response. The structure is as following:

struct http_response
{
struct parsed_url *request_uri;
char *body;
char *status_code;
int status_code_int;
char *status_text;
char *request_headers;
char *response_headers;
};

#####*request_uri
This is an instance of the parsed_url structure, this contains the request URL and all information about the request
URL. Look up parsed_url for more information.

#####*body
This contains the response BODY (usually HTML).

#####*status_code
This contains the HTTP Status code returned by the server in plain text format.

#####status_code_int
This returns the same as status_code but as an integer.

#####*status_text
http_response is a structure that is returned by _http_request_exec_ method, it contains information about the response.
Please note that this function returns a pointer to an instance of http_response. The structure is as following:

```c

typedef struct http_response {
http_header *headers;
char *body;
size_t body_len;
char *redirect_uri;
int redirect_count;
int status_code;
char *status_text;
} http_response;
```

##### *redirect_ui
The last redirected url.

##### *redirect_count
the HTTP redirect count

##### *body
The response body. always NULL if you set a response body callback

##### body_len
the response body length

##### status_code
the response HTTP status code

##### *status_text
This returns the text associated with the status code. For status code 200, OK will be returned.

#####*request_headers
This contains the HTTP headers that were used to make the request.
##### *headers
response HTTP headers as _struct http_header_ pointer.

#####*response_headers
Contains the HTTP headers returned by the server.
## HTTP response callback

http_req()
-------------
http_req is the basis for all other http_* methodes and makes and HTTP request and returns an instance of the http_response structure.
Provide an HTTP response body callback to handle large HTTP response payload efficiently.
this will avoid allocating memory to hold the response.

The prototype for this function is:
## full example

struct http_response* http_req(char *http_headers, struct parsed_url *purl)

A simple example is:

struct parsed_url *purl = parse_url("http://www.google.com/");
struct http_response *hrep = http_req("GET / HTTP/1.1\r\nHostname:www.google.com\r\nConnection:close\r\n\r\n", purl);
```c

Please note that http_req does not handle redirects. (Status code 300-399)
#include "http/client.h"

http_get()
-------------
Makes an HTTP GET request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers.

The prototype for this function is:

struct http_response* http_get(char *url, char *custom_headers)

A simple example is:

struct http_response *hresp = http_get("http://www.google.com", "User-agent:MyUserAgent\r\n");

http_get does handle redirects automaticly. The basic headers used in this method:

GET / HTTP/1.1
Hostname:www.google.com
Connection:close

http_post
------------
Makes an HTTP POST request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers. In the third parameter
the post data can be specified.

The prototype for this function is:

struct http_response* http_post(char *url, char *custom_headers, char *post_data)

A simple example is:

struct http_response *hresp = http_post("http://mywebsite.com/login.php", "User-agent:MyuserAgent\r\n", "username=Kirk&password=lol123");

http_post does handle redirects automaticly. The basic headers used in this method:

POST /login.php HTTP/1.1
Hostname:mywebsite.com
Connection:close

username=Kirk&password=lol123

FILE *fp;

/**
* response header callback
* @param headers
*/
void response_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers received:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* request header callback
* @param headers
*/
void request_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers sent:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* response body callback
* @param chunk
* @param chunk_len
* @param headers
*/
void response_body_cb(const char *chunk, size_t chunk_len, http_header *headers) {

if (chunk_len > 0) {

fwrite(chunk, 1, chunk_len, fp);

http_header *content_type = http_header_get(headers, "Content-Type");

// if text content, dump to stderr
if (content_type != NULL && strstr(content_type->value, "text/") != NULL) {

fwrite(chunk, chunk_len, 1, stderr);
}

http_header_free(content_type);
}
}

int main(int argc, char *argv[]) {

if (argc <= 2) {

fprintf(stderr, "Usage: \n$ %s URL DEST_FILE\n", argv[0]);
exit(1);
}

char *filename = argc > 2 ? argv[2] : "";
fprintf(stderr, "opening %s ...\n", filename);

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firevox");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

fp = fopen(filename, "wb");

http_response *response = http_request_exec(request);

fclose(fp);

http_request_free(request);
http_response_free(response);

return 0;
}
```
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' enable safe binary data transfer and fixed memory leaks by tbela99 · Pull Request #2 · langhai/http-client-c · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.21)
project(http_client_c C)

set(CMAKE_C_STANDARD 11)
add_compile_options(-fms-extensions)

include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/encoding)

#file(GLOB SOURCES
# ${SOURCES}/src/encoding/*
# )

add_executable(http_client_c
${CMAKE_SOURCE_DIR}/test/main.c
)

#add_executable(http_chunked_c
# ${CMAKE_SOURCE_DIR}/test/chunked.c
# )


target_link_libraries(http_client_c m)
#target_link_libraries(http_chunked_c m)
File renamed without changes.
311 changes: 226 additions & 85 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,98 +10,239 @@ in C, it can be used in C++ code as well.

Basic Usage
===============
http_response

```c
#include "http/client.h"

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
// add an HTTP header, replace existing
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
// add an HTTP header, keep existing
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

// execute the request
http_response *response = http_request_exec(request);

http_request_free(request);
http_response_free(response);
```

## http_request

the request structure.

```c

typedef struct http_request {
http_header *headers;
size_t body_len;
char *body;
char *request_uri;
int max_redirect;
char *method;
http_header_cb_ptr *request_header_cb;
http_header_cb_ptr *response_header_cb;
http_response_body_cb_ptr *response_body_cb;
struct timeval *request_timeout;
} http_request;

```

## create a request struct pointer.

```c
http_request *request = http_request_new();
```

## configure the request options

```c

// http_request *hreq - the request struct pointer
// http_option option - the option to configure
// const void *val - option payload
// size_t len - the payload length, only needed if the payload is a binary string, otherwise pass 0
// void http_request_option(http_request *hreq, http_option option, const void *val, size_t len)


http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");
```

### http option flags
- HTTP_OPTION_URL: pass the url
- HTTP_OPTION_HEADER: pass an HTTP header as a _struct http_header_ pointer
- HTTP_OPTION_BODY: pass the request payload
- HTTP_OPTION_METHOD: pass the HTTP method
- HTTP_OPTION_REQUEST_TIMEOUT: set the request timeout as a numeric string
- HTTP_OPTION_REQUEST_HEADER_CALLBACK: pass a request header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_HEADER_CALLBACK: pass a response header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_BODY_CALLBACK: pass a response body callback (see ./test/main.c for an example)

http_response
-------------
http_response is a structure that is returned by all http_* methods, it contains information about the requse and the response.
Please note that all functions return a pointer to an insance of http_response. The structure is as following:

struct http_response
{
struct parsed_url *request_uri;
char *body;
char *status_code;
int status_code_int;
char *status_text;
char *request_headers;
char *response_headers;
};

#####*request_uri
This is an instance of the parsed_url structure, this contains the request URL and all information about the request
URL. Look up parsed_url for more information.

#####*body
This contains the response BODY (usually HTML).

#####*status_code
This contains the HTTP Status code returned by the server in plain text format.

#####status_code_int
This returns the same as status_code but as an integer.

#####*status_text
http_response is a structure that is returned by _http_request_exec_ method, it contains information about the response.
Please note that this function returns a pointer to an instance of http_response. The structure is as following:

```c

typedef struct http_response {
http_header *headers;
char *body;
size_t body_len;
char *redirect_uri;
int redirect_count;
int status_code;
char *status_text;
} http_response;
```

##### *redirect_ui
The last redirected url.

##### *redirect_count
the HTTP redirect count

##### *body
The response body. always NULL if you set a response body callback

##### body_len
the response body length

##### status_code
the response HTTP status code

##### *status_text
This returns the text associated with the status code. For status code 200, OK will be returned.

#####*request_headers
This contains the HTTP headers that were used to make the request.
##### *headers
response HTTP headers as _struct http_header_ pointer.

#####*response_headers
Contains the HTTP headers returned by the server.
## HTTP response callback

http_req()
-------------
http_req is the basis for all other http_* methodes and makes and HTTP request and returns an instance of the http_response structure.
Provide an HTTP response body callback to handle large HTTP response payload efficiently.
this will avoid allocating memory to hold the response.

The prototype for this function is:
## full example

struct http_response* http_req(char *http_headers, struct parsed_url *purl)

A simple example is:

struct parsed_url *purl = parse_url("http://www.google.com/");
struct http_response *hrep = http_req("GET / HTTP/1.1\r\nHostname:www.google.com\r\nConnection:close\r\n\r\n", purl);
```c

Please note that http_req does not handle redirects. (Status code 300-399)
#include "http/client.h"

http_get()
-------------
Makes an HTTP GET request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers.

The prototype for this function is:

struct http_response* http_get(char *url, char *custom_headers)

A simple example is:

struct http_response *hresp = http_get("http://www.google.com", "User-agent:MyUserAgent\r\n");

http_get does handle redirects automaticly. The basic headers used in this method:

GET / HTTP/1.1
Hostname:www.google.com
Connection:close

http_post
------------
Makes an HTTP POST request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers. In the third parameter
the post data can be specified.

The prototype for this function is:

struct http_response* http_post(char *url, char *custom_headers, char *post_data)

A simple example is:

struct http_response *hresp = http_post("http://mywebsite.com/login.php", "User-agent:MyuserAgent\r\n", "username=Kirk&password=lol123");

http_post does handle redirects automaticly. The basic headers used in this method:

POST /login.php HTTP/1.1
Hostname:mywebsite.com
Connection:close

username=Kirk&password=lol123

FILE *fp;

/**
* response header callback
* @param headers
*/
void response_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers received:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* request header callback
* @param headers
*/
void request_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers sent:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* response body callback
* @param chunk
* @param chunk_len
* @param headers
*/
void response_body_cb(const char *chunk, size_t chunk_len, http_header *headers) {

if (chunk_len > 0) {

fwrite(chunk, 1, chunk_len, fp);

http_header *content_type = http_header_get(headers, "Content-Type");

// if text content, dump to stderr
if (content_type != NULL && strstr(content_type->value, "text/") != NULL) {

fwrite(chunk, chunk_len, 1, stderr);
}

http_header_free(content_type);
}
}

int main(int argc, char *argv[]) {

if (argc <= 2) {

fprintf(stderr, "Usage: \n$ %s URL DEST_FILE\n", argv[0]);
exit(1);
}

char *filename = argc > 2 ? argv[2] : "";
fprintf(stderr, "opening %s ...\n", filename);

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firevox");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

fp = fopen(filename, "wb");

http_response *response = http_request_exec(request);

fclose(fp);

http_request_free(request);
http_response_free(response);

return 0;
}
```
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' enable safe binary data transfer and fixed memory leaks by tbela99 · Pull Request #2 · langhai/http-client-c · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.21)
project(http_client_c C)

set(CMAKE_C_STANDARD 11)
add_compile_options(-fms-extensions)

include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/encoding)

#file(GLOB SOURCES
# ${SOURCES}/src/encoding/*
# )

add_executable(http_client_c
${CMAKE_SOURCE_DIR}/test/main.c
)

#add_executable(http_chunked_c
# ${CMAKE_SOURCE_DIR}/test/chunked.c
# )


target_link_libraries(http_client_c m)
#target_link_libraries(http_chunked_c m)
File renamed without changes.
311 changes: 226 additions & 85 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,98 +10,239 @@ in C, it can be used in C++ code as well.

Basic Usage
===============
http_response

```c
#include "http/client.h"

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
// add an HTTP header, replace existing
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
// add an HTTP header, keep existing
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

// execute the request
http_response *response = http_request_exec(request);

http_request_free(request);
http_response_free(response);
```

## http_request

the request structure.

```c

typedef struct http_request {
http_header *headers;
size_t body_len;
char *body;
char *request_uri;
int max_redirect;
char *method;
http_header_cb_ptr *request_header_cb;
http_header_cb_ptr *response_header_cb;
http_response_body_cb_ptr *response_body_cb;
struct timeval *request_timeout;
} http_request;

```

## create a request struct pointer.

```c
http_request *request = http_request_new();
```

## configure the request options

```c

// http_request *hreq - the request struct pointer
// http_option option - the option to configure
// const void *val - option payload
// size_t len - the payload length, only needed if the payload is a binary string, otherwise pass 0
// void http_request_option(http_request *hreq, http_option option, const void *val, size_t len)


http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");
```

### http option flags
- HTTP_OPTION_URL: pass the url
- HTTP_OPTION_HEADER: pass an HTTP header as a _struct http_header_ pointer
- HTTP_OPTION_BODY: pass the request payload
- HTTP_OPTION_METHOD: pass the HTTP method
- HTTP_OPTION_REQUEST_TIMEOUT: set the request timeout as a numeric string
- HTTP_OPTION_REQUEST_HEADER_CALLBACK: pass a request header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_HEADER_CALLBACK: pass a response header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_BODY_CALLBACK: pass a response body callback (see ./test/main.c for an example)

http_response
-------------
http_response is a structure that is returned by all http_* methods, it contains information about the requse and the response.
Please note that all functions return a pointer to an insance of http_response. The structure is as following:

struct http_response
{
struct parsed_url *request_uri;
char *body;
char *status_code;
int status_code_int;
char *status_text;
char *request_headers;
char *response_headers;
};

#####*request_uri
This is an instance of the parsed_url structure, this contains the request URL and all information about the request
URL. Look up parsed_url for more information.

#####*body
This contains the response BODY (usually HTML).

#####*status_code
This contains the HTTP Status code returned by the server in plain text format.

#####status_code_int
This returns the same as status_code but as an integer.

#####*status_text
http_response is a structure that is returned by _http_request_exec_ method, it contains information about the response.
Please note that this function returns a pointer to an instance of http_response. The structure is as following:

```c

typedef struct http_response {
http_header *headers;
char *body;
size_t body_len;
char *redirect_uri;
int redirect_count;
int status_code;
char *status_text;
} http_response;
```

##### *redirect_ui
The last redirected url.

##### *redirect_count
the HTTP redirect count

##### *body
The response body. always NULL if you set a response body callback

##### body_len
the response body length

##### status_code
the response HTTP status code

##### *status_text
This returns the text associated with the status code. For status code 200, OK will be returned.

#####*request_headers
This contains the HTTP headers that were used to make the request.
##### *headers
response HTTP headers as _struct http_header_ pointer.

#####*response_headers
Contains the HTTP headers returned by the server.
## HTTP response callback

http_req()
-------------
http_req is the basis for all other http_* methodes and makes and HTTP request and returns an instance of the http_response structure.
Provide an HTTP response body callback to handle large HTTP response payload efficiently.
this will avoid allocating memory to hold the response.

The prototype for this function is:
## full example

struct http_response* http_req(char *http_headers, struct parsed_url *purl)

A simple example is:

struct parsed_url *purl = parse_url("http://www.google.com/");
struct http_response *hrep = http_req("GET / HTTP/1.1\r\nHostname:www.google.com\r\nConnection:close\r\n\r\n", purl);
```c

Please note that http_req does not handle redirects. (Status code 300-399)
#include "http/client.h"

http_get()
-------------
Makes an HTTP GET request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers.

The prototype for this function is:

struct http_response* http_get(char *url, char *custom_headers)

A simple example is:

struct http_response *hresp = http_get("http://www.google.com", "User-agent:MyUserAgent\r\n");

http_get does handle redirects automaticly. The basic headers used in this method:

GET / HTTP/1.1
Hostname:www.google.com
Connection:close

http_post
------------
Makes an HTTP POST request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers. In the third parameter
the post data can be specified.

The prototype for this function is:

struct http_response* http_post(char *url, char *custom_headers, char *post_data)

A simple example is:

struct http_response *hresp = http_post("http://mywebsite.com/login.php", "User-agent:MyuserAgent\r\n", "username=Kirk&password=lol123");

http_post does handle redirects automaticly. The basic headers used in this method:

POST /login.php HTTP/1.1
Hostname:mywebsite.com
Connection:close

username=Kirk&password=lol123

FILE *fp;

/**
* response header callback
* @param headers
*/
void response_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers received:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* request header callback
* @param headers
*/
void request_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers sent:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* response body callback
* @param chunk
* @param chunk_len
* @param headers
*/
void response_body_cb(const char *chunk, size_t chunk_len, http_header *headers) {

if (chunk_len > 0) {

fwrite(chunk, 1, chunk_len, fp);

http_header *content_type = http_header_get(headers, "Content-Type");

// if text content, dump to stderr
if (content_type != NULL && strstr(content_type->value, "text/") != NULL) {

fwrite(chunk, chunk_len, 1, stderr);
}

http_header_free(content_type);
}
}

int main(int argc, char *argv[]) {

if (argc <= 2) {

fprintf(stderr, "Usage: \n$ %s URL DEST_FILE\n", argv[0]);
exit(1);
}

char *filename = argc > 2 ? argv[2] : "";
fprintf(stderr, "opening %s ...\n", filename);

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firevox");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

fp = fopen(filename, "wb");

http_response *response = http_request_exec(request);

fclose(fp);

http_request_free(request);
http_response_free(response);

return 0;
}
```
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); enable safe binary data transfer and fixed memory leaks by tbela99 · Pull Request #2 · langhai/http-client-c · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.21)
project(http_client_c C)

set(CMAKE_C_STANDARD 11)
add_compile_options(-fms-extensions)

include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/encoding)

#file(GLOB SOURCES
# ${SOURCES}/src/encoding/*
# )

add_executable(http_client_c
${CMAKE_SOURCE_DIR}/test/main.c
)

#add_executable(http_chunked_c
# ${CMAKE_SOURCE_DIR}/test/chunked.c
# )


target_link_libraries(http_client_c m)
#target_link_libraries(http_chunked_c m)
File renamed without changes.
311 changes: 226 additions & 85 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,98 +10,239 @@ in C, it can be used in C++ code as well.

Basic Usage
===============
http_response

```c
#include "http/client.h"

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
// add an HTTP header, replace existing
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
// add an HTTP header, keep existing
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

// execute the request
http_response *response = http_request_exec(request);

http_request_free(request);
http_response_free(response);
```

## http_request

the request structure.

```c

typedef struct http_request {
http_header *headers;
size_t body_len;
char *body;
char *request_uri;
int max_redirect;
char *method;
http_header_cb_ptr *request_header_cb;
http_header_cb_ptr *response_header_cb;
http_response_body_cb_ptr *response_body_cb;
struct timeval *request_timeout;
} http_request;

```

## create a request struct pointer.

```c
http_request *request = http_request_new();
```

## configure the request options

```c

// http_request *hreq - the request struct pointer
// http_option option - the option to configure
// const void *val - option payload
// size_t len - the payload length, only needed if the payload is a binary string, otherwise pass 0
// void http_request_option(http_request *hreq, http_option option, const void *val, size_t len)


http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firefox 12");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");
```

### http option flags
- HTTP_OPTION_URL: pass the url
- HTTP_OPTION_HEADER: pass an HTTP header as a _struct http_header_ pointer
- HTTP_OPTION_BODY: pass the request payload
- HTTP_OPTION_METHOD: pass the HTTP method
- HTTP_OPTION_REQUEST_TIMEOUT: set the request timeout as a numeric string
- HTTP_OPTION_REQUEST_HEADER_CALLBACK: pass a request header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_HEADER_CALLBACK: pass a response header callback (see ./test/main.c for an example)
- HTTP_OPTION_RESPONSE_BODY_CALLBACK: pass a response body callback (see ./test/main.c for an example)

http_response
-------------
http_response is a structure that is returned by all http_* methods, it contains information about the requse and the response.
Please note that all functions return a pointer to an insance of http_response. The structure is as following:

struct http_response
{
struct parsed_url *request_uri;
char *body;
char *status_code;
int status_code_int;
char *status_text;
char *request_headers;
char *response_headers;
};

#####*request_uri
This is an instance of the parsed_url structure, this contains the request URL and all information about the request
URL. Look up parsed_url for more information.

#####*body
This contains the response BODY (usually HTML).

#####*status_code
This contains the HTTP Status code returned by the server in plain text format.

#####status_code_int
This returns the same as status_code but as an integer.

#####*status_text
http_response is a structure that is returned by _http_request_exec_ method, it contains information about the response.
Please note that this function returns a pointer to an instance of http_response. The structure is as following:

```c

typedef struct http_response {
http_header *headers;
char *body;
size_t body_len;
char *redirect_uri;
int redirect_count;
int status_code;
char *status_text;
} http_response;
```

##### *redirect_ui
The last redirected url.

##### *redirect_count
the HTTP redirect count

##### *body
The response body. always NULL if you set a response body callback

##### body_len
the response body length

##### status_code
the response HTTP status code

##### *status_text
This returns the text associated with the status code. For status code 200, OK will be returned.

#####*request_headers
This contains the HTTP headers that were used to make the request.
##### *headers
response HTTP headers as _struct http_header_ pointer.

#####*response_headers
Contains the HTTP headers returned by the server.
## HTTP response callback

http_req()
-------------
http_req is the basis for all other http_* methodes and makes and HTTP request and returns an instance of the http_response structure.
Provide an HTTP response body callback to handle large HTTP response payload efficiently.
this will avoid allocating memory to hold the response.

The prototype for this function is:
## full example

struct http_response* http_req(char *http_headers, struct parsed_url *purl)

A simple example is:

struct parsed_url *purl = parse_url("http://www.google.com/");
struct http_response *hrep = http_req("GET / HTTP/1.1\r\nHostname:www.google.com\r\nConnection:close\r\n\r\n", purl);
```c

Please note that http_req does not handle redirects. (Status code 300-399)
#include "http/client.h"

http_get()
-------------
Makes an HTTP GET request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers.

The prototype for this function is:

struct http_response* http_get(char *url, char *custom_headers)

A simple example is:

struct http_response *hresp = http_get("http://www.google.com", "User-agent:MyUserAgent\r\n");

http_get does handle redirects automaticly. The basic headers used in this method:

GET / HTTP/1.1
Hostname:www.google.com
Connection:close

http_post
------------
Makes an HTTP POST request to the specified URL. This function makes use of the http_req function. It specifies
the minimal headers required, in the second parameter you can specify extra headers. In the third parameter
the post data can be specified.

The prototype for this function is:

struct http_response* http_post(char *url, char *custom_headers, char *post_data)

A simple example is:

struct http_response *hresp = http_post("http://mywebsite.com/login.php", "User-agent:MyuserAgent\r\n", "username=Kirk&password=lol123");

http_post does handle redirects automaticly. The basic headers used in this method:

POST /login.php HTTP/1.1
Hostname:mywebsite.com
Connection:close

username=Kirk&password=lol123

FILE *fp;

/**
* response header callback
* @param headers
*/
void response_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers received:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* request header callback
* @param headers
*/
void request_header_cb(http_header *headers) {

http_header *header = headers;

fprintf(stderr, "headers sent:\n");

char *printed = http_header_print(headers);

fprintf(stderr, "%s\r\n", printed);

fwrite(printed, strlen(printed), 1, fp);
fwrite("\r\n", 2, 1, fp);
free(printed);
}

/**
* response body callback
* @param chunk
* @param chunk_len
* @param headers
*/
void response_body_cb(const char *chunk, size_t chunk_len, http_header *headers) {

if (chunk_len > 0) {

fwrite(chunk, 1, chunk_len, fp);

http_header *content_type = http_header_get(headers, "Content-Type");

// if text content, dump to stderr
if (content_type != NULL && strstr(content_type->value, "text/") != NULL) {

fwrite(chunk, chunk_len, 1, stderr);
}

http_header_free(content_type);
}
}

int main(int argc, char *argv[]) {

if (argc <= 2) {

fprintf(stderr, "Usage: \n$ %s URL DEST_FILE\n", argv[0]);
exit(1);
}

char *filename = argc > 2 ? argv[2] : "";
fprintf(stderr, "opening %s ...\n", filename);

http_request *request = http_request_new();

http_request_option(request, HTTP_OPTION_URL, argv[1], 0);
// http_request_option(request, HTTP_OPTION_METHOD, "POST");
// http_request_option(request, HTTP_OPTION_BODY, "a=1&b=2");
http_request_option(request, HTTP_OPTION_REQUEST_TIMEOUT, "5", 0);
http_request_option(request, HTTP_OPTION_REQUEST_HEADER_CALLBACK, request_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_HEADER_CALLBACK, response_header_cb, 0);
http_request_option(request, HTTP_OPTION_RESPONSE_BODY_CALLBACK, response_body_cb, 0);
http_request_header_set(request, "User-Agent", "Firevox");
// http_request_header_set(request, "Authorization", "Bearer <secret>");
http_request_header_add(request, "Accept-Language", "en-US;q=0.6,en;q=0.4");

fp = fopen(filename, "wb");

http_response *response = http_request_exec(request);

fclose(fp);

http_request_free(request);
http_response_free(response);

return 0;
}
```
Loading