Objectively
Ultra-lightweight object oriented framework for GNU C.
Loading...
Searching...
No Matches
URLSessionTask.c File Reference
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <curl/curl.h>
#include "URLRequest.h"
#include "URLResponse.h"
#include "URLSession.h"
#include "URLSessionTask.h"

Go to the source code of this file.

Macros

#define _Class   _URLSessionTask
 

Functions

Class_URLSessionTask (void)
 
static void cancel (URLSessionTask *self)
 
static Objectcopy (const Object *self)
 
static void dealloc (Object *self)
 
static void execute (URLSessionTask *self)
 
static void initialize (Class *clazz)
 
static URLSessionTaskinitWithRequestInSession (URLSessionTask *self, struct URLRequest *request, struct URLSession *session, URLSessionTaskCompletion completion)
 
static int progress (ident self, curl_off_t bytesExpectedToReceive, curl_off_t bytesReceived, curl_off_t bytesExpectedToSend, curl_off_t bytesSent)
 The CURLOPT_XFERINFOFUNCTION, which updates internal state and dispatches the task's progress function.
 
static void requestHeaders_enumerator (const Dictionary *dictionary, ident obj, ident key, ident data)
 A helper to populate the request headers list for CURL.
 
static size_t responseHeader (char *buffer, size_t size, size_t count, void *data)
 The CURLOPT_HEADERFUNCTION for parsing response headers.
 
static void resume (URLSessionTask *self)
 
static void setup (URLSessionTask *self)
 
static void suspend (URLSessionTask *self)
 
static void teardown (URLSessionTask *self)
 

Macro Definition Documentation

◆ _Class

#define _Class   _URLSessionTask

Definition at line 34 of file URLSessionTask.c.

Function Documentation

◆ _URLSessionTask()

Class * _URLSessionTask ( void  )

Definition at line 342 of file URLSessionTask.c.

342 {
343 static Class *clazz;
344 static Once once;
345
346 do_once(&once, {
347 clazz = _initialize(&(const ClassDef) {
348 .name = "URLSessionTask",
349 .superclass = _Object(),
350 .instanceSize = sizeof(URLSessionTask),
351 .interfaceOffset = offsetof(URLSessionTask, interface),
352 .interfaceSize = sizeof(URLSessionTaskInterface),
354 });
355 });
356
357 return clazz;
358}
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:86
Class * _Object(void)
Definition Object.c:136
static void initialize(Class *clazz)
long Once
The Once type.
Definition Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition Class.h:41
The runtime representation of a Class.
Definition Class.h:95
URL session tasks are handles to pending URL operations.

◆ cancel()

static void cancel ( URLSessionTask self)
static

Definition at line 70 of file URLSessionTask.c.

70 {
71
72 switch (self->state) {
78 break;
79 default:
80 break;
81 }
82}
@ URLSESSIONTASK_RESUMING
@ URLSESSIONTASK_SUSPENDING
@ URLSESSIONTASK_SUSPENDED
@ URLSESSIONTASK_RESUMED
@ URLSESSIONTASK_CANCELING
URLSessionTaskState state
The state.

◆ copy()

static Object * copy ( const Object self)
static
See also
Object::copy(const Object *)

Definition at line 41 of file URLSessionTask.c.

41 {
42
43 return NULL;
44}

◆ dealloc()

static void dealloc ( Object self)
static
See also
Object::dealloc(Object *)

Definition at line 49 of file URLSessionTask.c.

49 {
50
51 URLSessionTask *this = (URLSessionTask *) self;
52
53 if (this->error) {
54 free(this->error);
55 }
56
57 release(this->request);
58 release(this->session);
59 release(this->response);
60
61 super(Object, self, dealloc);
62}
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition Class.c:195
#define super(type, obj, method,...)
static void error(const Log *self, const char *fmt,...)
Definition Log.c:80
static int request(RESTClient *self, HTTPMethod method, const char *url_string, const Data *body, Data **out_data)
Definition RESTClient.c:57
static void dealloc(Object *self)
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46

◆ execute()

static void execute ( URLSessionTask self)
static

Definition at line 88 of file URLSessionTask.c.

88 {
89
90 $(self, setup);
91
92 curl_easy_perform(self->locals.handle);
93
94 curl_easy_getinfo(self->locals.handle, CURLINFO_RESPONSE_CODE, (long *) &self->response->httpStatusCode);
95
97
98 $(self, teardown);
99}
static void teardown(void)
Called atexit to teardown Objectively.
Definition Class.c:46
static void setup(void)
Called when initializing Object to setup Objectively.
Definition Class.c:73
@ URLSESSIONTASK_COMPLETED
int httpStatusCode
The HTTP response status code.
Definition URLResponse.h:63
struct URLResponse * response
The response.
ident handle
The backing libcurl handle.

◆ initialize()

static void initialize ( Class clazz)
static
See also
Class::initialize(Class *)

Definition at line 324 of file URLSessionTask.c.

324 {
325
326 ((ObjectInterface *) clazz->interface)->copy = copy;
327 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
328
329 ((URLSessionTaskInterface *) clazz->interface)->cancel = cancel;
330 ((URLSessionTaskInterface *) clazz->interface)->execute = execute;
331 ((URLSessionTaskInterface *) clazz->interface)->initWithRequestInSession = initWithRequestInSession;
332 ((URLSessionTaskInterface *) clazz->interface)->resume = resume;
333 ((URLSessionTaskInterface *) clazz->interface)->setup = setup;
334 ((URLSessionTaskInterface *) clazz->interface)->suspend = suspend;
335 ((URLSessionTaskInterface *) clazz->interface)->teardown = teardown;
336}
static URLSessionTask * initWithRequestInSession(URLSessionTask *self, struct URLRequest *request, struct URLSession *session, URLSessionTaskCompletion completion)
static void resume(URLSessionTask *self)
static void cancel(URLSessionTask *self)
static void execute(URLSessionTask *self)
static Object * copy(const Object *self)
static void suspend(URLSessionTask *self)
ident interface
The interface of the Class.
Definition Class.h:105
void dealloc(Object *self)
Frees all resources held by this Object.
Definition Array.c:99
void resume(URLSessionTask *)
Starts or resumes this task.

◆ initWithRequestInSession()

static URLSessionTask * initWithRequestInSession ( URLSessionTask self,
struct URLRequest request,
struct URLSession session,
URLSessionTaskCompletion  completion 
)
static

Definition at line 105 of file URLSessionTask.c.

106 {
107
108 assert(request);
109 assert(session);
110
111 self = (URLSessionTask *) super(Object, self, init);
112 if (self) {
113
114 self->error = calloc(1, CURL_ERROR_SIZE);
115 assert(self->error);
116
117 self->request = retain(request);
118 self->session = retain(session);
119
120 self->response = $(alloc(URLResponse), init);
121
122 self->completion = completion;
123
125 }
126
127 return self;
128}
static Array * init(Array *self)
Definition Array.c:420
ident retain(ident obj)
Atomically increment the given Object's reference count.
Definition Class.c:210
#define alloc(type)
Allocate and initialize and instance of type.
Definition Class.h:176
A protocol-agnostic abstraction for URLSessionTask responses.
Definition URLResponse.h:42
char * error
The error buffer.
struct URLRequest * request
The request.
struct URLSession * session
The session.
URLSessionTaskCompletion completion
The completion function.

◆ progress()

static int progress ( ident  self,
curl_off_t  bytesExpectedToReceive,
curl_off_t  bytesReceived,
curl_off_t  bytesExpectedToSend,
curl_off_t  bytesSent 
)
static

The CURLOPT_XFERINFOFUNCTION, which updates internal state and dispatches the task's progress function.

Remarks
This is also the mechanism for resuming suspended tasks.

Definition at line 190 of file URLSessionTask.c.

191 {
192
193 URLSessionTask *this = (URLSessionTask *) self;
194
195 curl_easy_getinfo(this->locals.handle, CURLINFO_RESPONSE_CODE, (long *) &this->response->httpStatusCode);
196
197 this->bytesExpectedToReceive = bytesExpectedToReceive;
198 this->bytesExpectedToSend = bytesExpectedToSend;
199
200 if (this->progress) {
201 this->progress(this);
202 }
203
204 return 0;
205}
static int progress(ident self, curl_off_t bytesExpectedToReceive, curl_off_t bytesReceived, curl_off_t bytesExpectedToSend, curl_off_t bytesSent)
The CURLOPT_XFERINFOFUNCTION, which updates internal state and dispatches the task's progress functio...

◆ requestHeaders_enumerator()

static void requestHeaders_enumerator ( const Dictionary dictionary,
ident  obj,
ident  key,
ident  data 
)
static

A helper to populate the request headers list for CURL.

Definition at line 149 of file URLSessionTask.c.

149 {
150
151 String *header = $(alloc(String), initWithFormat, "%s: %s", ((String * ) key)->chars, ((String * ) obj)->chars);
152
153 struct curl_slist **headers = (struct curl_slist **) data;
154 *headers = curl_slist_append(*headers, header->chars);
155
156 release(header);
157}
#define obj
static Data * data(void)
Definition Data.c:286
static DateFormatter * initWithFormat(DateFormatter *self, const char *fmt)
UTF-8 strings.
Definition String.h:69
char * chars
The backing null-terminated UTF-8 encoded character array.
Definition String.h:85

◆ responseHeader()

static size_t responseHeader ( char *  buffer,
size_t  size,
size_t  count,
void *  data 
)
static

The CURLOPT_HEADERFUNCTION for parsing response headers.

Definition at line 162 of file URLSessionTask.c.

162 {
163
165
166 char *header = calloc(count + 1, 1);
167 memcpy(header, buffer, count);
168
169 char *delim = strchr(header, ':');
170 if (delim) {
171 *delim = 0;
172
173 char *field = header;
174 char *value = strtrim(delim + 1);
175
176 $(this->response, setValueForHTTPHeaderField, value, field);
177
178 free(value);
179 }
180
181 free(header);
182 return count;
183}
char * strtrim(const char *s)
Copies the given null-terminated C string, trimming leading and trailing whitespace.
Definition String.c:1097
static void setValueForHTTPHeaderField(URLRequest *self, const char *value, const char *field)
Definition URLRequest.c:169

◆ resume()

static void resume ( URLSessionTask self)
static

Definition at line 134 of file URLSessionTask.c.

134 {
135
136 switch (self->state) {
140 break;
141 default:
142 break;
143 }
144}

◆ setup()

static void setup ( URLSessionTask self)
static

Definition at line 211 of file URLSessionTask.c.

211 {
212
213 self->locals.handle = curl_easy_init();
214 assert(self->locals.handle);
215
216 curl_easy_setopt(self->locals.handle, CURLOPT_ERRORBUFFER, self->error);
217 curl_easy_setopt(self->locals.handle, CURLOPT_FOLLOWLOCATION, true);
218
219 const URLSessionConfiguration *config = self->session->configuration;
220 if (config->connectTimeout) {
221 curl_easy_setopt(self->locals.handle, CURLOPT_CONNECTTIMEOUT, config->connectTimeout);
222 }
223 if (config->timeout) {
224 curl_easy_setopt(self->locals.handle, CURLOPT_TIMEOUT, config->timeout);
225 }
226 if (!config->longPolling) {
227 curl_easy_setopt(self->locals.handle, CURLOPT_LOW_SPEED_LIMIT, 1L);
228 curl_easy_setopt(self->locals.handle, CURLOPT_LOW_SPEED_TIME, 10L);
229 }
230
231 curl_easy_setopt(self->locals.handle, CURLOPT_HEADERFUNCTION, responseHeader);
232 curl_easy_setopt(self->locals.handle, CURLOPT_HEADERDATA, self);
233
234 curl_easy_setopt(self->locals.handle, CURLOPT_XFERINFOFUNCTION, progress);
235 curl_easy_setopt(self->locals.handle, CURLOPT_XFERINFODATA, self);
236
237 Data *body = self->request->httpBody;
238 if (body) {
239 curl_easy_setopt(self->locals.handle, CURLOPT_POSTFIELDS, body->bytes);
240 curl_easy_setopt(self->locals.handle, CURLOPT_POSTFIELDSIZE, body->length);
241 }
242
243 struct curl_slist *httpHeaders = NULL;
244 const Dictionary *headers = NULL;
245
246 headers = self->session->configuration->httpHeaders;
247 if (headers) {
248 $(headers, enumerateObjectsAndKeys, requestHeaders_enumerator, &httpHeaders);
249 }
250
251 headers = self->request->httpHeaders;
252 if (headers) {
253 $(headers, enumerateObjectsAndKeys, requestHeaders_enumerator, &httpHeaders);
254 }
255
256 curl_easy_setopt(self->locals.handle, CURLOPT_HTTPHEADER, httpHeaders);
257
258 self->locals.requestHeaders = httpHeaders;
259
260 switch (self->request->httpMethod) {
261 case HTTP_POST:
262 curl_easy_setopt(self->locals.handle, CURLOPT_POST, true);
263 break;
264 case HTTP_PUT:
265 curl_easy_setopt(self->locals.handle, CURLOPT_PUT, true);
266 break;
267 case HTTP_DELETE:
268 curl_easy_setopt(self->locals.handle, CURLOPT_CUSTOMREQUEST, "DELETE");
269 break;
270 case HTTP_PATCH:
271 curl_easy_setopt(self->locals.handle, CURLOPT_CUSTOMREQUEST, "PATCH");
272 break;
273 case HTTP_HEAD:
274 curl_easy_setopt(self->locals.handle, CURLOPT_NOBODY, true);
275 break;
276 case HTTP_OPTIONS:
277 curl_easy_setopt(self->locals.handle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
278 break;
279 default:
280 break;
281 }
282
283 curl_easy_setopt(self->locals.handle, CURLOPT_URL, self->request->url->urlString->chars);
284}
static void enumerateObjectsAndKeys(const Dictionary *self, DictionaryEnumerator enumerator, ident data)
Definition Dictionary.c:295
@ HTTP_PUT
Definition URLRequest.h:48
@ HTTP_DELETE
Definition URLRequest.h:50
@ HTTP_OPTIONS
Definition URLRequest.h:45
@ HTTP_POST
Definition URLRequest.h:47
@ HTTP_HEAD
Definition URLRequest.h:44
@ HTTP_PATCH
Definition URLRequest.h:49
static void requestHeaders_enumerator(const Dictionary *dictionary, ident obj, ident key, ident data)
A helper to populate the request headers list for CURL.
static size_t responseHeader(char *buffer, size_t size, size_t count, void *data)
The CURLOPT_HEADERFUNCTION for parsing response headers.
Data buffers.
Definition Data.h:50
size_t length
The length of bytes.
Definition Data.h:76
uint8_t * bytes
The bytes.
Definition Data.h:66
Key-value stores.
Definition Dictionary.h:60
String * urlString
The URL String.
Definition URL.h:90
HTTPMethod httpMethod
The HTTP request method.
Definition URLRequest.h:84
Dictionary * httpHeaders
The HTTP request headers.
Definition URLRequest.h:79
URL * url
The URL.
Definition URLRequest.h:89
Data * httpBody
The HTTP request body, sent as POST or PUT data.
Definition URLRequest.h:74
Configuration bundle for URLSession.
long connectTimeout
The timeout interval for establishing a connection, in seconds. 0 means no limit.
Dictionary * httpHeaders
The HTTP headers added to every HTTP URLRequest.
bool longPolling
If true, disables stall detection (LOW_SPEED_LIMIT / LOW_SPEED_TIME). Use for requests that legitimat...
long timeout
The timeout for the entire transfer, in seconds. 0 means no limit.
URLSessionConfiguration * configuration
The session configuration.
Definition URLSession.h:98
ident requestHeaders
HTTP headers, in libcurl list structure.

◆ suspend()

static void suspend ( URLSessionTask self)
static

Definition at line 290 of file URLSessionTask.c.

290 {
291
292 switch (self->state) {
296 break;
297 default:
298 break;
299 }
300}

◆ teardown()

static void teardown ( URLSessionTask self)
static

Definition at line 306 of file URLSessionTask.c.

306 {
307
308 if (self->locals.handle) {
309 curl_easy_cleanup(self->locals.handle);
310 self->locals.handle = NULL;
311 }
312
313 if (self->locals.requestHeaders) {
314 curl_slist_free_all(self->locals.requestHeaders);
315 self->locals.requestHeaders = NULL;
316 }
317}