ObjFW  Check-in [9ed387bacb]

Overview
Comment:Add OFHTTPRequestDelegate.
This allows status updates etc.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 9ed387bacb282b7e7870c8a0c797a7f7b7c63863b4606174b040c8199c5a67a7
User & Date: js on 2011-04-22 14:13:30
Other Links: manifest | tags
Context
2011-04-22
14:35
OFHTTPRequest: Make it possible to not store the data in an OFDataArray. check-in: 1cc6f3659f user: js tags: trunk
14:13
Add OFHTTPRequestDelegate.
This allows status updates etc.
check-in: 9ed387bacb user: js tags: trunk
2011-04-21
11:28
Added tag 0.5.1-release for changeset aa44cb415cea check-in: a1ffc85a28 user: js tags: trunk
Changes

Modified src/OFHTTPRequest.h from [3154174ff6] to [50bcc3a5fa].

15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30























































31
32
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
 */

#import "OFObject.h"

@class OFString;
@class OFDictionary;
@class OFURL;

@class OFHTTPRequestResult;
@class OFDataArray;

typedef enum of_http_request_type_t {
	OF_HTTP_REQUEST_TYPE_GET,
	OF_HTTP_REQUEST_TYPE_POST,
	OF_HTTP_REQUEST_TYPE_HEAD
} of_http_request_type_t;
























































/**
 * \brief A class for storing and performing HTTP requests.
 */
@interface OFHTTPRequest: OFObject
{
	OFURL *URL;
	of_http_request_type_t requestType;
	OFString *queryString;
	OFDictionary *headers;
	BOOL redirectsFromHTTPSToHTTPAllowed;

}

#ifdef OF_HAVE_PROPERTIES
@property (copy) OFURL *URL;
@property (assign) of_http_request_type_t requestType;
@property (copy) OFString *queryString;
@property (copy) OFDictionary *headers;
@property (assign) BOOL redirectsFromHTTPSToHTTPAllowed;

#endif

/**
 * \return A new, autoreleased OFHTTPRequest
 */
+ request;








>









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










>








>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
 */

#import "OFObject.h"

@class OFString;
@class OFDictionary;
@class OFURL;
@class OFHTTPRequest;
@class OFHTTPRequestResult;
@class OFDataArray;

typedef enum of_http_request_type_t {
	OF_HTTP_REQUEST_TYPE_GET,
	OF_HTTP_REQUEST_TYPE_POST,
	OF_HTTP_REQUEST_TYPE_HEAD
} of_http_request_type_t;

/**
 * \brief A delegate for OFHTTPRequests.
 */
#ifndef OF_HTTP_REQUEST_M
@protocol OFHTTPRequestDelegate <OFObject>
#else
@protocol OFHTTPRequestDelegate
#endif
#ifdef OF_HAVE_OPTIONAL_PROTOCOLS
@optional
#endif
/**
 * This callback is called when the OFHTTPRequest received the headers.
 *
 * \param request The OFHTTPRequest which received the headers
 * \param headers The headers received
 * \param statusCode The status code received
 */
-     (void)request: (OFHTTPRequest*)request
  didReceiveHeaders: (OFDictionary*)headers
     withStatusCode: (int)statusCode;

/**
 * This callback is called when the OFHTTPRequest received data.
 *
 * This is useful for example if you want to update a status display.
 *
 * \param request The OFHTTPRequest which received data
 * \param data The data the OFHTTPRequest received
 * \param len The length of the data received, in bytes
 */
-  (void)request: (OFHTTPRequest*)request
  didReceiveData: (const char*)data
      withLength: (size_t)len;

/**
 * This callback is called when the OFHTTPRequest will follow a redirect.
 *
 * If you want to get the headers and data for each redirect, set the number of
 * redirects to 0 and perform a new OFHTTPRequest for each redirect. However,
 * this callback will not be called then and you have to look at the status code
 * to detect a redirect.
 *
 * This callback will only be called if the OFHTTPRequest will follow a
 * redirect. If the maximum number of redirects has been reached already, this
 * callback will not be called.
 *
 * \param request The OFHTTPRequest which will follow a redirect
 * \param url The URL to which it will follow a redirect
 * \return A boolean whether the OFHTTPRequest should follow the redirect
 */
-	 (BOOL)request: (OFHTTPRequest*)request
  willFollowRedirectTo: (OFURL*)url;
@end

/**
 * \brief A class for storing and performing HTTP requests.
 */
@interface OFHTTPRequest: OFObject
{
	OFURL *URL;
	of_http_request_type_t requestType;
	OFString *queryString;
	OFDictionary *headers;
	BOOL redirectsFromHTTPSToHTTPAllowed;
	id <OFHTTPRequestDelegate> delegate;
}

#ifdef OF_HAVE_PROPERTIES
@property (copy) OFURL *URL;
@property (assign) of_http_request_type_t requestType;
@property (copy) OFString *queryString;
@property (copy) OFDictionary *headers;
@property (assign) BOOL redirectsFromHTTPSToHTTPAllowed;
@property (retain) id <OFHTTPRequestDelegate> delegate;
#endif

/**
 * \return A new, autoreleased OFHTTPRequest
 */
+ request;

123
124
125
126
127
128
129












130
131
132
133
134
135
136
- (void)setRedirectsFromHTTPSToHTTPAllowed: (BOOL)allowed;

/**
 * \return Whether redirects from HTTPS to HTTP are allowed
 */
- (BOOL)redirectsFromHTTPSToHTTPAllowed;













/**
 * Performs the HTTP request and returns an OFHTTPRequestResult.
 *
 * \return An OFHTTPRequestResult with the result of the HTTP request
 */
- (OFHTTPRequestResult*)perform;








>
>
>
>
>
>
>
>
>
>
>
>







181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
- (void)setRedirectsFromHTTPSToHTTPAllowed: (BOOL)allowed;

/**
 * \return Whether redirects from HTTPS to HTTP are allowed
 */
- (BOOL)redirectsFromHTTPSToHTTPAllowed;

/**
 * Sets the delegate for the HTTP request.
 *
 * \param delegate The delegate for the HTTP request
 */
- (void)setDelegate: (id <OFHTTPRequestDelegate>)delegate;

/**
 * \return The delegate for the HTTP request.
 */
- (id <OFHTTPRequestDelegate>)delegate;

/**
 * Performs the HTTP request and returns an OFHTTPRequestResult.
 *
 * \return An OFHTTPRequestResult with the result of the HTTP request
 */
- (OFHTTPRequestResult*)perform;

178
179
180
181
182
183
184
185



186
- (OFDictionary*)headers;

/**
 * \return The data returned for the HTTP request
 */
- (OFDataArray*)data;
@end




extern Class of_http_request_tls_socket_class;








>
>
>

248
249
250
251
252
253
254
255
256
257
258
259
- (OFDictionary*)headers;

/**
 * \return The data returned for the HTTP request
 */
- (OFDataArray*)data;
@end

@interface OFObject (OFHTTPRequestDelegate) <OFHTTPRequestDelegate>
@end

extern Class of_http_request_tls_socket_class;

Modified src/OFHTTPRequest.m from [c8b35b7eac] to [f1713b1a20].

12
13
14
15
16
17
18


19
20
21
22
23
24
25

26
27
28
29
30
31
32
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"



#include <string.h>

#import "OFHTTPRequest.h"
#import "OFString.h"
#import "OFURL.h"
#import "OFTCPSocket.h"
#import "OFDictionary.h"

#import "OFAutoreleasePool.h"

#import "OFHTTPRequestFailedException.h"
#import "OFInvalidServerReplyException.h"
#import "OFOutOfRangeException.h"
#import "OFTruncatedDataException.h"
#import "OFUnsupportedProtocolException.h"







>
>







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#define OF_HTTP_REQUEST_M

#include <string.h>

#import "OFHTTPRequest.h"
#import "OFString.h"
#import "OFURL.h"
#import "OFTCPSocket.h"
#import "OFDictionary.h"
#import "OFDataArray.h"
#import "OFAutoreleasePool.h"

#import "OFHTTPRequestFailedException.h"
#import "OFInvalidServerReplyException.h"
#import "OFOutOfRangeException.h"
#import "OFTruncatedDataException.h"
#import "OFUnsupportedProtocolException.h"
127
128
129
130
131
132
133










134
135
136
137
138
139
140
	redirectsFromHTTPSToHTTPAllowed = allowed;
}

- (BOOL)redirectsFromHTTPSToHTTPAllowed
{
	return redirectsFromHTTPSToHTTPAllowed;
}











- (OFHTTPRequestResult*)perform
{
	return [self performWithRedirects: 10];
}

- (OFHTTPRequestResult*)performWithRedirects: (size_t)redirects







>
>
>
>
>
>
>
>
>
>







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
	redirectsFromHTTPSToHTTPAllowed = allowed;
}

- (BOOL)redirectsFromHTTPSToHTTPAllowed
{
	return redirectsFromHTTPSToHTTPAllowed;
}

- (void)setDelegate: (id <OFHTTPRequestDelegate>)delegate_
{
	OF_SETTER(delegate, delegate_, YES, NO)
}

- (id <OFHTTPRequestDelegate>)delegate
{
	OF_GETTER(delegate, YES)
}

- (OFHTTPRequestResult*)perform
{
	return [self performWithRedirects: 10];
}

- (OFHTTPRequestResult*)performWithRedirects: (size_t)redirects
164
165
166
167
168
169
170

171
172
173
174
175
176
177
		OFString *line, *path;
		OFMutableDictionary *s_headers;
		OFDataArray *data;
		OFEnumerator *enumerator;
		OFString *key;
		int status;
		const char *t = NULL;


		[sock connectToHost: [URL host]
			     onPort: [URL port]];

		/*
		 * Work around a bug with packet bisection in lighttpd when
		 * using HTTPS.







>







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
		OFString *line, *path;
		OFMutableDictionary *s_headers;
		OFDataArray *data;
		OFEnumerator *enumerator;
		OFString *key;
		int status;
		const char *t = NULL;
		char *buf;

		[sock connectToHost: [URL host]
			     onPort: [URL port]];

		/*
		 * Work around a bug with packet bisection in lighttpd when
		 * using HTTPS.
270
271
272
273
274
275
276

277
278
279











280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299



300
















301
302
303
304
305
306
307
			if ((redirects > 0 && (status == 301 || status == 302 ||
			    status == 303) && [key caseInsensitiveCompare:
			    @"Location"] == OF_ORDERED_SAME) &&
			    (redirectsFromHTTPSToHTTPAllowed ||
			    [scheme isEqual: @"http"] ||
			    ![value hasPrefix: @"http://"])) {
				OFURL *new;


				new = [[OFURL alloc] initWithString: value
						      relativeToURL: URL];











				[URL release];
				URL = new;

				if (status == 303) {
					requestType = OF_HTTP_REQUEST_TYPE_GET;
					[queryString release];
					queryString = nil;
				}

				[pool release];
				pool = nil;

				return [self performWithRedirects:
				    redirects - 1];
			}

			[s_headers setObject: value
				      forKey: key];
		}




		data = [sock readDataArrayTillEndOfStream];

















		if ([s_headers objectForKey: @"Content-Length"] != nil) {
			intmax_t cl;

			cl = [[s_headers objectForKey: @"Content-Length"]
			    decimalValue];








>

|
|
>
>
>
>
>
>
>
>
>
>
>




















>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
			if ((redirects > 0 && (status == 301 || status == 302 ||
			    status == 303) && [key caseInsensitiveCompare:
			    @"Location"] == OF_ORDERED_SAME) &&
			    (redirectsFromHTTPSToHTTPAllowed ||
			    [scheme isEqual: @"http"] ||
			    ![value hasPrefix: @"http://"])) {
				OFURL *new;
				BOOL follow;

				new = [OFURL URLWithString: value
					     relativeToURL: URL];

				follow = [delegate request: self
				      willFollowRedirectTo: new];

				if (!follow && delegate != nil) {
					[s_headers setObject: value
						      forKey: key];
					continue;
				}

				new = [new retain];
				[URL release];
				URL = new;

				if (status == 303) {
					requestType = OF_HTTP_REQUEST_TYPE_GET;
					[queryString release];
					queryString = nil;
				}

				[pool release];
				pool = nil;

				return [self performWithRedirects:
				    redirects - 1];
			}

			[s_headers setObject: value
				      forKey: key];
		}

		[delegate request: self
		didReceiveHeaders: s_headers
		   withStatusCode: status];

		data = [OFDataArray dataArrayWithItemSize: 1];
		buf = [self allocMemoryWithSize: of_pagesize];
		@try {
			size_t len;

			while ((len = [sock readNBytes: of_pagesize
					    intoBuffer: buf]) > 0) {
				[data addNItems: len
				     fromCArray: buf];
				[delegate request: self
				   didReceiveData: buf
				       withLength: len];
			}
		} @finally {
			[self freeMemory: buf];
		}

		if ([s_headers objectForKey: @"Content-Length"] != nil) {
			intmax_t cl;

			cl = [[s_headers objectForKey: @"Content-Length"]
			    decimalValue];

367
368
369
370
371
372
373




















}

- (OFDataArray*)data
{
	return [[data retain] autorelease];
}
@end



























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
}

- (OFDataArray*)data
{
	return [[data retain] autorelease];
}
@end

@implementation OFObject (OFHTTPRequestDelegate)
-     (void)request: (OFHTTPRequest*)request
  didReceiveHeaders: (OFDictionary*)headers
     withStatusCode: (int)statusCode
{
}

-  (void)request: (OFHTTPRequest*)request
  didReceiveData: (const char*)data
      withLength: (size_t)len
{
}

-	 (BOOL)request: (OFHTTPRequest*)request
  willFollowRedirectTo: (OFURL*)url
{
	return YES;
}
@end