@@ -11,13 +11,13 @@ REBOL [
11
11
}
12
12
Name: 'http
13
13
Type: 'module
14
- Version: 0.1.0
14
+ Version: 0.1.4
15
15
File: %prot-http.r
16
16
Purpose: {
17
17
This program defines the HTTP protocol scheme for REBOL 3.
18
18
}
19
- Author: "Gabriele Santilli"
20
- Date: 22-Jun-2007
19
+ Author: [ "Gabriele Santilli" "Richard Smolak" ]
20
+ Date: 26-Nov-2012
21
21
]
22
22
23
23
sync-op : func [ port body /local state] [
@@ -26,7 +26,13 @@ sync-op: func [port body /local state] [
26
26
state/awake: :read-sync-awake
27
27
do body
28
28
if state/state = 'ready [do-request port]
29
- unless port? wait [state/connection port/spec/timeout ] [http-error "Timeout" ]
29
+ ;NOTE: We'll wait in a WHILE loop so the timeout cannot occur during 'reading-data state.
30
+ ;The timeout should be triggered only when the response from other side exceeds the timeout value.
31
+ ;--Richard
32
+ while [not find [ready close] state/state ][
33
+ unless port? wait [state/connection port/spec/timeout ] [http-error "Timeout" ]
34
+ if state/state = 'reading-data [read state/connection ]
35
+ ]
30
36
body: copy port
31
37
if state/close? [close port]
32
38
body
@@ -88,6 +94,8 @@ http-awake: func [event /local port http-port state awake res] [
88
94
state/error: make-http-error "Server closed connection"
89
95
awake make event! [type: 'error port: http-port]
90
96
] [
97
+ ;set state to CLOSE so the WAIT loop in 'sync-op can be interrupted --Richard
98
+ state/state: 'close
91
99
any [
92
100
awake make event! [type: 'done port: http-port]
93
101
awake make event! [type: 'close port: http-port]
@@ -152,7 +160,7 @@ do-request: func [
152
160
spec/headers: body-of make make object! [
153
161
Accept: "*/*"
154
162
Accept-Charset: "utf-8"
155
- Host: either spec/port-id <> 80 [
163
+ Host: either not find [ 80 443 ] spec/port-id [
156
164
rejoin [form spec/host #":" spec/port-id ]
157
165
] [
158
166
form spec/host
@@ -249,6 +257,11 @@ check-response: func [port /local conn res headers d1 d2 line info state awake s
249
257
res: awake make event! [type: 'custom port: port code: 0 ]
250
258
] [
251
259
res: check-data port
260
+ unless open? port [
261
+ ;NOTE some servers(e.g. yahoo.com) don't supply content-data in the redirect header so the state/state can be left in 'reading-data after check-data call
262
+ ;I think it is better to check if port has been closed here and set the state so redirect sequence can happen. --Richard
263
+ state/state: 'ready
264
+ ]
252
265
]
253
266
if all [not res state/state = 'ready] [
254
267
either all [
@@ -328,16 +341,26 @@ do-redirect: func [port [port!] new-uri [url! string! file!] /local spec state]
328
341
if #"/" = first new-uri [
329
342
new-uri: to url! ajoin [spec/scheme "://" spec/host new-uri]
330
343
]
331
- new-uri: construct /with decode-url new-uri port/scheme/spec
332
- if new-uri/scheme <> 'http [
333
- state/error: make-http-error {Redirect to a protocol different from HTTP not supported}
344
+ new-uri: decode-url new-uri
345
+ unless select new-uri 'port-id [
346
+ switch new-uri/scheme [
347
+ 'https [append new-uri [port-id: 443 ]]
348
+ 'http [append new-uri [port-id: 80 ]]
349
+ ]
350
+ ]
351
+ new-uri: construct /with new-uri port/scheme/spec
352
+ unless find [http https] new-uri/scheme [
353
+ state/error: make-http-error {Redirect to a protocol different from HTTP or HTTPS not supported}
334
354
return state/awake make event! [type: 'error port: port]
335
355
]
336
356
either all [
337
357
new-uri/host = spec/host
338
358
new-uri/port-id = spec/port-id
339
359
] [
340
360
spec/path: new-uri/path
361
+ ;we need to reset tcp connection here before doing a redirect
362
+ close port/state/connection
363
+ open port/state/connection
341
364
do-request port
342
365
false
343
366
] [
@@ -353,12 +376,14 @@ check-data: func [port /local headers res data out chunk-size mk1 mk2 trailer st
353
376
case [
354
377
headers/transfer-encoding = "chunked" [
355
378
data: conn/data
356
- out: port/data: make binary! length? data
379
+ ;clear the port data only at the beginning of the request --Richard
380
+ unless port/data [port/data: make binary! length? data]
381
+ out: port/data
357
382
until [
358
383
either parse/all data [
359
384
copy chunk-size some hex-digits thru crlfbin mk1: to end
360
385
] [
361
- chunk-size: to integer! to issue! chunk-size
386
+ chunk-size: to integer! to issue! to string! chunk-size
362
387
either chunk-size = 0 [
363
388
if parse/all mk1 [
364
389
crlfbin (trailer: "" ) to end | copy trailer to crlf2bin to end
@@ -385,7 +410,10 @@ check-data: func [port /local headers res data out chunk-size mk1 mk2 trailer st
385
410
true
386
411
]
387
412
]
388
- unless state/state = 'ready [read conn]
413
+ unless state/state = 'ready [
414
+ ;Awake from the WAIT loop to prevent timeout when reading big data. --Richard
415
+ res: true
416
+ ]
389
417
]
390
418
integer? headers/content-length [
391
419
port/data: conn/data
@@ -394,12 +422,19 @@ check-data: func [port /local headers res data out chunk-size mk1 mk2 trailer st
394
422
conn/data: make binary! 32000
395
423
res: state/awake make event! [type: 'custom port: port code: 0 ]
396
424
] [
397
- read conn
425
+ ;Awake from the WAIT loop to prevent timeout when reading big data. --Richard
426
+ res: true
398
427
]
399
428
]
400
429
true [
401
430
port/data: conn/data
402
- read conn
431
+ either state/info/response-parsed = 'ok [
432
+ ;Awake from the WAIT loop to prevent timeout when reading big data. --Richard
433
+ res: true
434
+ ][
435
+ ;On other response than OK read all data asynchronously (assuming the data are small). --Richard
436
+ read conn
437
+ ]
403
438
]
404
439
]
405
440
res
@@ -465,8 +500,8 @@ sys/make-scheme [
465
500
info: make port/scheme/info [type: 'file]
466
501
awake: : port/awake
467
502
]
468
- port/state/connection: conn: make port! [
469
- scheme: ' tcp
503
+ port/state/connection: conn: make port! compose [
504
+ scheme: ( to lit-word! either port /spec/scheme = 'http [' tcp]['tls])
470
505
host: port/spec/host
471
506
port-id: port/spec/port-id
472
507
ref: rejoin [tcp:// host ":" port-id]
@@ -520,3 +555,11 @@ sys/make-scheme [
520
555
]
521
556
]
522
557
]
558
+
559
+ sys/make-scheme/with [
560
+ name: 'https
561
+ title: "Secure HyperText Transport Protocol v1.1"
562
+ spec: make spec [
563
+ port-id: 443
564
+ ]
565
+ ] 'http
0 commit comments