Objectively 1.0.0
Ultra-lightweight object oriented framework for GNU C.
Macros | Functions
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. More...
 
static void requestHeaders_enumerator (const Dictionary *dictionary, ident obj, ident key, ident data)
 A helper to populate the request headers list for CURL. More...
 
static size_t responseHeader (char *buffer, size_t size, size_t count, void *data)
 The CURLOPT_HEADERFUNCTION for parsing response headers. More...
 
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 324 of file URLSessionTask.c.

324 {
325 static Class *clazz;
326 static Once once;
327
328 do_once(&once, {
329 clazz = _initialize(&(const ClassDef) {
330 .name = "URLSessionTask",
331 .superclass = _Object(),
332 .instanceSize = sizeof(URLSessionTask),
333 .interfaceOffset = offsetof(URLSessionTask, interface),
334 .interfaceSize = sizeof(URLSessionTaskInterface),
336 });
337 });
338
339 return clazz;
340}
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition: Class.c:91
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
Class * _Object(void)
The Object archetype.
Definition: Object.c:136
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:196
#define super(type, obj, method,...)
void error(const Log *self, const char *fmt,...)
Log an error message.
Definition: Log.c:80
Object is the root Class of The Objectively Class hierarchy.
Definition: Object.h:46
void dealloc(Object *self)
Frees all resources held by this Object.
Definition: Array.c:50

◆ 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}
@ URLSESSIONTASK_COMPLETED
int httpStatusCode
The HTTP response status code.
Definition: URLResponse.h:63
struct URLResponse * response
The response.
ident handle
The backing libcurl handle.
void setup(URLSessionTask *)
Sets up this task.
void teardown(URLSessionTask *)
Tears down this task.

◆ initialize()

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

Definition at line 306 of file URLSessionTask.c.

306 {
307
308 ((ObjectInterface *) clazz->interface)->copy = copy;
309 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
310
311 ((URLSessionTaskInterface *) clazz->interface)->cancel = cancel;
312 ((URLSessionTaskInterface *) clazz->interface)->execute = execute;
313 ((URLSessionTaskInterface *) clazz->interface)->initWithRequestInSession = initWithRequestInSession;
314 ((URLSessionTaskInterface *) clazz->interface)->resume = resume;
315 ((URLSessionTaskInterface *) clazz->interface)->setup = setup;
316 ((URLSessionTaskInterface *) clazz->interface)->suspend = suspend;
317 ((URLSessionTaskInterface *) clazz->interface)->teardown = teardown;
318}
ident interface
The interface of the Class.
Definition: Class.h:105
Object * copy(const Object *self)
Creates a shallow copy of this Object.
Definition: Array.c:40
void cancel(Operation *self)
Cancels this Operation, allowing it to complete immediately.
Definition: Operation.c:74
URLSessionTask * initWithRequestInSession(URLSessionTask *, struct URLRequest *, struct URLSession *, URLSessionTaskCompletion)
Initializes this task with the given URLRequest.
void resume(URLSessionTask *)
Starts or resumes this task.
void suspend(URLSessionTask *)
Suspends this task.
void execute(URLSessionTask *)
Executes this task synchronously, on the calling thread.

◆ 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}
ident retain(ident obj)
Atomically increment the given Object's reference count.
Definition: Class.c:211
#define alloc(type)
Allocate and initialize and instance of type.
Definition: Class.h:159
Condition * init(Condition *self)
Initializes this Condition.
Definition: Condition.c:67
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
DateFormatter * initWithFormat(DateFormatter *self, const char *fmt)
Initializes a DateFormatter with the specified format string.
Definition: DateFormatter.c:76
MutableData * data(void)
Returns a new MutableData.
Definition: MutableData.c:75
Immutable 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:752
void setValueForHTTPHeaderField(URLREquest *self, const char *value, const char *field)

◆ 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 curl_easy_setopt(self->locals.handle, CURLOPT_HEADERFUNCTION, responseHeader);
220 curl_easy_setopt(self->locals.handle, CURLOPT_HEADERDATA, self);
221
222 curl_easy_setopt(self->locals.handle, CURLOPT_XFERINFOFUNCTION, progress);
223 curl_easy_setopt(self->locals.handle, CURLOPT_XFERINFODATA, self);
224
225 Data *body = self->request->httpBody;
226 if (body) {
227 curl_easy_setopt(self->locals.handle, CURLOPT_POSTFIELDS, body->bytes);
228 curl_easy_setopt(self->locals.handle, CURLOPT_POSTFIELDSIZE, body->length);
229 }
230
231 struct curl_slist *httpHeaders = NULL;
232 const Dictionary *headers = NULL;
233
234 headers = self->session->configuration->httpHeaders;
235 if (headers) {
236 $(headers, enumerateObjectsAndKeys, requestHeaders_enumerator, &httpHeaders);
237 }
238
239 headers = self->request->httpHeaders;
240 if (headers) {
241 $(headers, enumerateObjectsAndKeys, requestHeaders_enumerator, &httpHeaders);
242 }
243
244 curl_easy_setopt(self->locals.handle, CURLOPT_HTTPHEADER, httpHeaders);
245
246 self->locals.requestHeaders = httpHeaders;
247
248 switch (self->request->httpMethod) {
249 case HTTP_POST:
250 curl_easy_setopt(self->locals.handle, CURLOPT_POST, true);
251 break;
252 case HTTP_PUT:
253 curl_easy_setopt(self->locals.handle, CURLOPT_PUT, true);
254 break;
255 case HTTP_DELETE:
256 curl_easy_setopt(self->locals.handle, CURLOPT_CUSTOMREQUEST, "DELETE");
257 break;
258 case HTTP_HEAD:
259 curl_easy_setopt(self->locals.handle, CURLOPT_NOBODY, true);
260 break;
261 default:
262 break;
263 }
264
265 curl_easy_setopt(self->locals.handle, CURLOPT_URL, self->request->url->urlString->chars);
266}
@ HTTP_PUT
Definition: URLRequest.h:46
@ HTTP_DELETE
Definition: URLRequest.h:47
@ HTTP_POST
Definition: URLRequest.h:45
@ HTTP_HEAD
Definition: URLRequest.h:48
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.
Immutable 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
Immutable key-value stores.
Definition: Dictionary.h:60
void enumerateObjectsAndKeys(const Dictionary *self, DictionaryEnumerator enumerator, ident data)
Enumerate the pairs of this Dictionary with the given function.
Definition: Dictionary.c:253
String * urlString
The URL String.
Definition: URL.h:90
HTTPMethod httpMethod
The HTTP request method.
Definition: URLRequest.h:82
Dictionary * httpHeaders
The HTTP request headers.
Definition: URLRequest.h:77
URL * url
The URL.
Definition: URLRequest.h:87
Data * httpBody
The HTTP request body, sent as POST or PUT data.
Definition: URLRequest.h:72
Dictionary * httpHeaders
The HTTP headers added to every HTTP URLRequest.
URLSessionConfiguration * configuration
The session configuration.
Definition: URLSession.h:103
ident requestHeaders
HTTP headers, in libcurl list structure.

◆ suspend()

static void suspend ( URLSessionTask self)
static

Definition at line 272 of file URLSessionTask.c.

272 {
273
274 switch (self->state) {
278 break;
279 default:
280 break;
281 }
282}

◆ teardown()

static void teardown ( URLSessionTask self)
static

Definition at line 288 of file URLSessionTask.c.

288 {
289
290 if (self->locals.handle) {
291 curl_easy_cleanup(self->locals.handle);
292 self->locals.handle = NULL;
293 }
294
295 if (self->locals.requestHeaders) {
296 curl_slist_free_all(self->locals.requestHeaders);
297 self->locals.requestHeaders = NULL;
298 }
299}