Objectively
Ultra-lightweight object oriented framework for GNU C.
Loading...
Searching...
No Matches
URLSessionDataTask.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include <assert.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include <curl/curl.h>
29
30#include "URLSession.h"
31#include "URLCache.h"
32#include "Data.h"
33#include "URLSessionDataTask.h"
34
35#define _Class _URLSessionDataTask
36
37#pragma mark - Object
38
42static void dealloc(Object *self) {
43
45
46 release(this->cachedResponse);
47 release(this->data);
48
49 super(Object, self, dealloc);
50}
51
52#pragma mark - URLSessionTask
53
58
59 if (self->cachedResponse == NULL) {
60 return;
61 }
62
65
66 release(self->data);
67 self->data = (Data *) $((Object *) self->cachedResponse->data, copy);
68
72 self->urlSessionTask.bytesSent = 0;
73
75 self->cachedResponse = NULL;
76}
77
83
84 if (self->cachedResponse) {
85 return;
86 }
87
89 if (cache) {
91 }
92}
93
97static void cancel(URLSessionTask *self) {
98
100
101 if (this->cachedResponse) {
102 if (this->urlSessionTask.state != URLSESSIONTASK_COMPLETED) {
103 release(this->cachedResponse);
104 this->cachedResponse = NULL;
105 this->urlSessionTask.state = URLSESSIONTASK_CANCELED;
106 }
107
108 return;
109 }
110
112}
113
117static void execute(URLSessionTask *self) {
118
119 URLSessionDataTask *this = (URLSessionDataTask *) self;
120
121 if (this->urlSessionTask.state == URLSESSIONTASK_CANCELED
122 || this->urlSessionTask.state == URLSESSIONTASK_COMPLETED) {
123 return;
124 }
125
126 if (this->cachedResponse) {
128 this->urlSessionTask.state = URLSESSIONTASK_COMPLETED;
129 return;
130 }
131
132 $(self, setup);
133
134 CURLcode code = curl_easy_perform(self->locals.handle);
135
136 curl_easy_getinfo(self->locals.handle, CURLINFO_RESPONSE_CODE, (long *) &self->response->httpStatusCode);
137
138 this->urlSessionTask.state = URLSESSIONTASK_COMPLETED;
139
140 if (code == CURLE_OK) {
141 $(this, cacheResponse);
142 }
143
144 $(self, teardown);
145}
146
150static void resume(URLSessionTask *self) {
151
152 URLSessionDataTask *this = (URLSessionDataTask *) self;
153
154 if (this->cachedResponse) {
155 switch (this->urlSessionTask.state) {
160 this->urlSessionTask.state = URLSESSIONTASK_COMPLETED;
161
162 if (this->urlSessionTask.completion) {
163 this->urlSessionTask.completion((URLSessionTask *) this, true);
164 }
165 break;
166 default:
167 break;
168 }
169
170 return;
171 }
172
174}
175
179static size_t writeFunction(char *data, size_t size, size_t count, ident self) {
180
181 URLSessionDataTask *this = (URLSessionDataTask *) self;
182
183 const uint8_t *bytes = (uint8_t *) data;
184 const size_t bytesReceived = size * count;
185
186 if (this->data == NULL) {
187 this->data = (Data *) $(alloc(Data), init);
188 }
189
190 $((Data *) this->data, appendBytes, bytes, bytesReceived);
191
192 this->urlSessionTask.bytesReceived += bytesReceived;
193 return bytesReceived;
194}
195
199static void setup(URLSessionTask *self) {
200
201 super(URLSessionTask, self, setup);
202
203 curl_easy_setopt(self->locals.handle, CURLOPT_WRITEFUNCTION, writeFunction);
204 curl_easy_setopt(self->locals.handle, CURLOPT_WRITEDATA, self);
205}
206
207#pragma mark - Class lifecycle
208
212static void initialize(Class *clazz) {
213
214 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
215
216 ((URLSessionTaskInterface *) clazz->interface)->cancel = cancel;
217 ((URLSessionTaskInterface *) clazz->interface)->execute = execute;
218 ((URLSessionTaskInterface *) clazz->interface)->setup = setup;
219 ((URLSessionTaskInterface *) clazz->interface)->resume = resume;
220
221 ((URLSessionDataTaskInterface *) clazz->interface)->cacheResponse = cacheResponse;
222}
223
229 static Class *clazz;
230 static Once once;
231
232 do_once(&once, {
233 clazz = _initialize(&(const ClassDef) {
234 .name = "URLSessionDataTask",
235 .superclass = _URLSessionTask(),
236 .instanceSize = sizeof(URLSessionDataTask),
237 .interfaceOffset = offsetof(URLSessionDataTask, interface),
238 .interfaceSize = sizeof(URLSessionDataTaskInterface),
240 });
241 });
242
243 return clazz;
244}
245
246#undef _Class
static Object * copy(const Object *self)
Definition Array.c:84
static Array * init(Array *self)
Definition Array.c:420
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
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition Class.c:195
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:86
#define alloc(type)
Allocate and initialize and instance of type.
Definition Class.h:176
#define super(type, obj, method,...)
static Data * data(void)
Definition Data.c:286
static void appendBytes(Data *self, const uint8_t *bytes, size_t length)
Definition Data.c:262
Data buffers.
UTF-8 strings.
void * ident
The identity type, similar to Objective-C id.
Definition Types.h:49
static void storeCachedResponseForRequest(URLCache *self, const URLRequest *request, const URLResponse *response, const Data *data)
Definition URLCache.c:356
A cache for HTTP responses.
A management context for loading resources via URLs.
Class * _URLSessionDataTask(void)
static size_t writeFunction(char *data, size_t size, size_t count, ident self)
The CURLOPT_WRITEFUNCTION callback.
static void resume(URLSessionTask *self)
static void materializeCachedResponse(URLSessionDataTask *self)
Copies a cached response into this task's live response and data fields.
static void cancel(URLSessionTask *self)
static void cacheResponse(URLSessionDataTask *self)
static void execute(URLSessionTask *self)
static void dealloc(Object *self)
static void initialize(Class *clazz)
Use data tasks to send and receive Data in-memory.
Class * _URLSessionTask(void)
@ URLSESSIONTASK_RESUMING
@ URLSESSIONTASK_CANCELED
@ URLSESSIONTASK_SUSPENDING
@ URLSESSIONTASK_SUSPENDED
@ URLSESSIONTASK_COMPLETED
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
ident interface
The interface of the Class.
Definition Class.h:105
Data buffers.
Definition Data.h:50
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46
A cache for HTTP responses.
Definition URLCache.h:44
URLResponse * response
The HTTP response.
Data * data
The response body.
size_t size
The cached body size.
A protocol-agnostic abstraction for URLSessionTask responses.
Definition URLResponse.h:42
int httpStatusCode
The HTTP response status code.
Definition URLResponse.h:63
URLCache * urlCache
The cache for URL responses, or NULL to disable caching.
Use data tasks to send and receive Data in-memory.
URLCachedResponse * cachedResponse
A cached response, if this task was fulfilled from URLCache.
Data * data
The data received.
URLSessionTask urlSessionTask
The superclass.
URLSessionConfiguration * configuration
The session configuration.
Definition URLSession.h:98
URL session tasks are handles to pending URL operations.
struct URLResponse * response
The response.
ident handle
The backing libcurl handle.
size_t bytesExpectedToSend
The count of bytes this task expects to send.
struct URLRequest * request
The request.
size_t bytesReceived
The count of bytes received.
struct URLSession * session
The session.
size_t bytesSent
The count of bytes sent.
size_t bytesExpectedToReceive
The count of bytes this task expects to receive.