COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/net/http.e91181.82%18721985.39%32
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
get_http()465485.19%8
get_recvheader()81361.54%5
get_sendheader()81361.54%5
set_sendheader()71258.33%5
set_sendheader_useragent_msie()030.00%3
eunet_format_sendheader()323494.12%2
get_http_use_cookie()020.00%2
eunet_parse()222395.65%1
get_url()121392.31%1
parse_recvheader()1313100.00%0
set_sendheader_default()1313100.00%0
LINE COVERAGE DETAIL
#Executed
1
--****
2
-- == HTTP
3
--
4
-- <>
5
6
namespace http
7
8
include std/socket.e as sock
9
include std/net/url.e
10
include std/net/dns.e
11
include std/text.e
12
include std/get.e as val
13
include euphoria/info.e
14
15
--****
16
-- === Constants
17
18
public constant
191
HTTP_HEADER_HTTPVERSION = 1,
201
HTTP_HEADER_GET = 2,
211
HTTP_HEADER_HOST = 3,
221
HTTP_HEADER_REFERER = 4,
231
HTTP_HEADER_USERAGENT = 5,
241
HTTP_HEADER_ACCEPT = 6,
251
HTTP_HEADER_ACCEPTCHARSET = 7,
261
HTTP_HEADER_ACCEPTENCODING = 8,
271
HTTP_HEADER_ACCEPTLANGUAGE = 9,
281
HTTP_HEADER_ACCEPTRANGES = 10,
291
HTTP_HEADER_AUTHORIZATION = 11,
301
HTTP_HEADER_DATE = 12,
311
HTTP_HEADER_IFMODIFIEDSINCE = 13,
321
HTTP_HEADER_POST = 14,
331
HTTP_HEADER_POSTDATA = 15,
341
HTTP_HEADER_CONTENTTYPE = 16,
351
HTTP_HEADER_CONTENTLENGTH = 17,
361
HTTP_HEADER_FROM = 18,
371
HTTP_HEADER_KEEPALIVE = 19,
381
HTTP_HEADER_CACHECONTROL = 20,
391
HTTP_HEADER_CONNECTION = 21
40
41
sequence
421
this_cookiejar = {},
431
sendheader = {}, -- HTTP header sequence , sent to somewhere (usually the server)
441
recvheader = {}, -- HTTP header sequence , received from somewhere (usually the server)
451
defaultsendheader = {} -- a list of what may be sent in the sendheader, and minimum typical values
46
473
48
integer slen, spt, flag
49
sequence parsed, upperc, uppers
50
513
upperc = ""
523
uppers = ""
53
543
if atom(c) then
550
c = {c}
56
end if
57
583
parsed = {}
593
slen = length(s)
603
spt = 1
613
flag = 0
62
633
upperc = upper(c)
643
uppers = upper(s)
653
for i = 1 to slen do
66800
if find(uppers[i],upperc) then
6752
if flag = 1 then
6826
parsed = append(parsed,s[spt..i-1])
6926
flag = 0
7026
spt = i+1
71
else
7226
spt += 1
73
end if
74
else
75748
flag = 1
76
end if
77800
end for
78
793
if flag = 1 then
803
parsed = append(parsed,s[spt..slen])
81
end if
82
833
return parsed
84
end function
85
86
--****
87
-- === Header management
88
--
89
90
--**
91
-- Retrieve either the whole sendheader sequence, or just a single
92
-- field.
93
--
94
-- Parameters:
95
-- # ##field## : an object indicating which part is being requested, see Comments section.
96
--
97
-- Returns:
98
-- An **object**, either:
99
-- * -1 if the field cannot be found,
100
-- * ##{{"label","delimiter","value"},...}## for the whole sendheader sequence
101
-- * a three-element sequence in the form ##{"label","delimiter","value"}## when only a single field is selected.
102
--
103
-- Comments:
104
-- ##field## can be either an HTTP_HEADER_xxx access constant,
105
-- the number 0 to retrieve the whole sendheader sequence, or
106
-- a string matching one of the header field labels. The string is
107
-- not case sensitive.
108
--
109
11075
111
-- if field is 0, return the whole sequence.
112
-- if field is 1..length(sendheader), return just that field
113
-- if field is invalid, return -1. -- no, this is a problem , some code needs a sequence
114
-- if field is a sequence, try to match it to sendheader[x][1].
115
116
-- Kat: should i return [1] & [2] as well? Mike: yes
117
-- most server interfaces return the only value, saves parsing
118
-- we'll return a {"Name","spacer","value"} format
119
120
sequence upperfield
121
12275
if sequence(field) then
12375
upperfield = upper(field)
12475
for idx = 1 to length(sendheader) do
125549
if equal(upperfield,upper(sendheader[idx][1])) then
12657
return sendheader[idx]
127
end if
128492
end for
12918
return {"","",""}
1300
elsif field < 0 or field > length(sendheader) then
1310
return {"","",""}
1320
elsif field = 0 then
1330
return sendheader
134
else
1350
return sendheader[field]
136
end if
137
end function
138
139
--**
140
-- Sets header elements to default values. The default User Agent
141
-- is Opera (currently the most standards compliant). Before setting
142
-- any header option individually, programs must call this procedure.
143
--
144
-- See Also:
145
-- [[:get_sendheader]], [[:set_sendheader]], [[:set_sendheader_useragent_msie]]
146
1474
1484
sequence tempnewheader = {}
1494
sequence temps = ""
1504
sequence whoami = "OpenEuphoria " & version_string_long()
151
152
-- this sets some defaults, if not previously set to something by the user
153
-- if a header line was previously set by the user, do not change it here
154
-- httpversion MUST come before GET in this program: some servers default to 1.0, even if you say 1.1
155
-- NO spaces around [3] on httpversion
156
-- POSTDATA MUST come before Content-Length in this program
157
-- Referer is often used by sites to be sure your fetch was from one of their own pages
158
-- headers with [3] = "" won't be sent
159
-- you can add more [1], and modify [3], [2] is the ' ' or ": " (GET and POST have no ": ")
160
1614
defaultsendheader = {
162
{"httpversion","","HTTP/1.0"}, -- not a legal http headerline, but to append to GET or POST later on
163
{"GET"," ",""}, -- [3] = the filename you want
164
{"POST"," ",""}, -- [3] = the filename you want
165
{"Host",": ",""}, -- the domain. You might think this was obvious, but for vhosting sites it's necessary.
166
{"Referer",": ",""}, -- i know it's misspelled, but that's official! , the site that sent you to this one
167
{"User-Agent",": ", whoami},
168
{"Accept-Charset",": ","utf-8,ISO-8859-1;q=0.7,*;q=0.5"},
169
{"Accept-Ranges",": ",""},
170
{"Authorization",": ",""},
171
{"Date",": ",""}, -- who cares if the server has my time? Except for cookie timeouts, that is.
172
{"If-Modified-Since",": ",""}, -- for keeping a local cache sync'd
173
{"POSTDATA","",""}, -- not a legal headerline, but has to go somewhere; put the POST data here, it will be appended to the bottom later
174
{"Content-Type",": ",""}, -- if POST or PUT transaction
175
{"Content-Length",": ",""}, -- if POST or PUT transaction
176
{"From",": ",""}, -- possible in POST or PUT or Authorization
177
{"Keep-Alive",": ",""}, -- set value depending on Connection
178
{"Cache-Control",": ",""},
179
{"Connection",": ","close"} -- this is usually "close", sometimes "keep-alive" for http/1.1 and SSL, even if you set "close" the server may ignore you
180
}
181
182
183
-- the following not only puts the default header lines,
184
-- it sorts the already-set lines to match the defaultsendheader order
1854
for defaultndx = 1 to length(defaultsendheader) do -- loop through defaultsendheader
18672
temps = get_sendheader(defaultsendheader[defaultndx][1]) -- see if it was already set to something
18772
if equal(temps[1],"") then
18818
tempnewheader &= {defaultsendheader[defaultndx]} -- so set the default line
189
else
19054
tempnewheader &= {temps} -- use the pre-definition
191
end if
19272
end for
193
1944
sendheader = tempnewheader
1954
end procedure
196
197
--**
198
-- Set an individual header field.
199
--
200
-- Parameters:
201
-- # ##whatheader## : an object, either an explicit name string or a HTTP_HEADER_xxx constant
202
-- # ##whatdata## : a string, the associated data
203
--
204
-- Comments:
205
-- If the requested field is not one of the default header fields,
206
-- the field MUST be set by string. This will increase the length
207
-- of the header overall.
208
--
209
-- Example 1:
210
--
211
-- set_sendheader("Referer","search.yahoo.com")
212
--
213
--
214
-- See Also:
215
-- [[:get_sendheader]]
216
21726
21826
if atom(whatheader) then
2190
if whatheader > 0 and whatheader <= length(sendheader) then -- how does this work?
2200
sendheader[whatheader][3] = whatdata
221
end if
2220
return
223
end if
224
22526
for idx = 1 to length(sendheader) do
226
-- is this whatheader already in sendheader?
227214
if match(upper(whatheader),upper(sendheader[idx][1])) then
228
-- then simply set it to this value
22926
sendheader[idx][3] = whatdata
23026
return
231
end if
232188
end for
233
234
-- ok, if we got here, then whatheader isn't in sendheader
235
236
-- you better know what you are doing here!
237
-- ": " is supplied as default, lets hope it's not an aberration like GET or POST
238
-- this doesn't put it in any correct order
2390
sendheader = append(sendheader,{whatheader, ": ",whatdata})
2400
end procedure
241
242
--**
243
-- Inform listener that user agent is Microsoft (R) Internet Explorer (TM).
244
--
245
-- Comments:
246
-- This is a convenience procedure to tell a website that a Microsoft
247
-- Internet Explorer (TM) browser is requesting data. Because some
248
-- websites format their response differently (or simply refuse data)
249
-- depending on the browser, this procedure provides a quick means
250
-- around that.
251
-- For example, see:
252
-- http://www.missporters.org/podium/nonsupport.aspx
253
2540
2550
set_sendheader("User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)")
2560
end procedure
257
258
--------------------------------------------------------------------------------
259
-- this can also be used to flatten the sendheader record, for printing, etc
2603
261
sequence
2623
tempheader = "",
2633
temppostdata = "",
2643
httpversion = ""
265
2663
for idx = 1 to length(sendheader) do
26754
if not equal("httpversion",sendheader[idx][1]) and
268
not equal("POSTDATA",sendheader[idx][1])
269
then
270
-- if the data field is not empty...
27148
if not equal("",sendheader[idx][3]) then
27218
switch sendheader[idx][1] with fallthru do
273
case "GET" then
274
-- remove any trailing nulls
2752
while find(0, sendheader[idx][3]) do
2763
sendheader[idx][3][find(0, sendheader[idx][3])] = ' '
2773
end while
278
-- append the http version
2792
tempheader &= sendheader[idx][1] & sendheader[idx][2] &
280
sendheader[idx][3] & " " & httpversion & "\r\n"
2812
break
282
283
case "POST" then
284
-- remove any trailing nulls
2851
while find(0, sendheader[idx][3]) do
2861
sendheader[idx][3][find(0, sendheader[idx][3])] = ' '
2871
end while
288
-- append the http version
2891
tempheader &= sendheader[idx][1] & sendheader[idx][2] &
290
sendheader[idx][3] & " " & httpversion & "\r\n"
2911
break
292
293
case else
294
-- remove any trailing nulls
29515
while find(0, sendheader[idx][3]) do
2960
sendheader[idx][3][find(0, sendheader[idx][3])] = ' '
2970
end while
298
-- else just flatten the sequence
29915
tempheader &= sendheader[idx][1] & sendheader[idx][2] &
300
sendheader[idx][3] & "\r\n"
301
end switch
302
end if
303
end if
304
305
-- this is done here because
306
-- this is where the POSTDATA is moved to the bottom of the header,
307
-- the Content-length and Content-Type is filled in
308
30954
if equal("POSTDATA",sendheader[idx][1]) and not equal("",sendheader[idx][3]) then
310
-- POSTDATA was set to something
3111
set_sendheader("Content-Type","application/x-www-form-urlencoded")
3121
temppostdata = sendheader[idx][3]
3131
set_sendheader("Content-Length",sprintf("%d",length(temppostdata)))
3141
sendheader[idx][3] = "" -- clear it, so it's not accidentally sent again
315
end if
316
31754
if equal("httpversion",sendheader[idx][1]) and not equal("",sendheader[idx][3]) then
3183
httpversion = sendheader[idx][3]
319
end if
32054
end for
321
3223
tempheader &= "\r\n" -- end of header
3233
if not equal(temppostdata,"") then-- but if there's POST data,
3241
tempheader = tempheader & temppostdata & "\r\n" -- tack that on too
325
end if
326
3273
return tempheader
328
end function
329
330
--**
331
-- Populates the internal sequence recvheader from the flat string header.
332
--
333
-- Parameters:
334
-- # ##header## : a string, the header data
335
--
336
-- Comments:
337
-- This must be called prior to calling [[:get_recvheader]]().
338
3393
340
sequence junk
341
atom place
342
3433
junk = {"",""} -- init it, it looks like this
3443
recvheader = eunet_parse(header,{10,13}) -- could be \n or \r or both
3453
for idx = 1 to length(recvheader) do
34629
place = match(": ",recvheader[idx])
34729
if place then
34826
junk[1] = recvheader[idx][1..place-1]
34926
junk[2] = recvheader[idx][place+2 .. $]
35026
recvheader[idx] = junk
351
else
3523
if match("HTTP/",upper(recvheader[idx])) then
3533
recvheader[idx] = {"httpversion",recvheader[idx]} -- what else to call that line?
354
end if
355
end if
35629
end for
3573
end procedure
358
359
--**
360
-- Return the value of a named field in the received http header as
361
-- returned by the most recent call to [[:get_http]].
362
--
363
-- Parameters:
364
-- # ##field## : an object, either a string holding a field name (case insensitive),
365
-- 0 to return the whole header, or a numerical index.
366
--
367
-- Returns:
368
-- An **object**,
369
-- * -1 on error
370
-- * a sequence in the form, ##{field name, field value}## on success.
371
3723
373
sequence upperfield
374
-- recvheader was parsed out previously in parse_recvheader()
375
-- if field is 0, return the whole sequence.
376
-- if field is 1..length(recvheader), return just that field
377
-- if field is invalid, return -1.
378
-- if field is a sequence, try to match it to recvheader[x][1].
379
380
-- we'll NOT return a {"Name","value"} format
381
-- because that leads to using a junk seq to get the [2] from
382
-- --> And yet, that's exactly what we're doing. -- Mike.
383
3843
if sequence(field) and equal(field,"") then
3850
return -1
386
end if
387
3883
if atom(field) then
3890
if ( field <= 0 ) or ( field > length(recvheader) ) then
3900
return -1
391
end if
392
3930
return recvheader[field]
394
end if
395
3963
upperfield = upper(field)
3973
for idx = 1 to length(recvheader) do
39827
if equal(upperfield,upper(recvheader[idx][1])) then
3993
return recvheader[idx] -- {"header_name","value"}
400
end if
40124
end for
402
4030
return -1 -- not found!
404
end function
405
406
--****
407
-- === Web interface
408
--
409
410
--**
411
-- Returns data from an http internet site.
412
--
413
-- Parameters:
414
-- # ##inet_addr## : a sequence holding an address
415
-- # ##hostname## : a string, the name for the host
416
-- # ##file## : a file name to transmit
417
--
418
-- Returns:
419
-- A **sequence**, empty sequence on error, of length 2 on success,
420
-- like ##{sequence header, sequence data}##.
421
4223
423
object junk, junk2, header
424
sock:socket sock
425
atom success, last_data_len, gotheader, contentlen, last
426
sequence data
427
428
-- Notes for future additions:
429
-- HUGE differences in HTTP/1.1 vs HTTP/1.0
430
-- GET /index.html HTTP/1.1
431
4323
if length(inet_addr)=0 then
4330
return {"",""}
434
end if
435
4363
if length(file)=0 or file[1]!='/' then
4371
file = '/' & file
438
end if
439
4403
junk = get_sendheader("POSTDATA")
441
-- was the POSTDATA set?
4423
if equal(junk[3],"") then
443
-- if no, assume it's a GET
4442
set_sendheader("GET",file)
445
else
446
-- if so, then it's definitely a POST (err, or PUT, but we don't do PUT)
4471
set_sendheader("POST",file)
448
end if
449
450
-- This is required for virtual shared hosting. On dedicated boxes on fixed ip,
451
-- you can http to the ip, and GET/POST is enough to deal with it. Setting it is
452
-- safe, either way.
4533
set_sendheader("HOST",hostname)
454
4553
last_data_len = 0
4563
sock = sock:create(AF_INET,SOCK_STREAM,0)
4573
success = sock:connect(sock,inet_addr,port)
458
4593
if success = sock:OK then
460
-- eunet_format_sendheader sets up the header to sent,
461
-- putting the POST data at the end,
462
-- filling in the CONTENT-LENGTH,
463
-- and avoiding sending empty fields for any field
4643
success = sock:send(sock,eunet_format_sendheader(),0)
465
466
-- } end version 1.3.0 mod
4673
data = ""
4683
header= {}
4693
contentlen = 0
4703
gotheader = 0
4713
if success
472
then
4733
last = time()
4743
while sequence(junk) with entry do
4753
data = data & junk
4763
if gotheader and equal(contentlen,length(data)) then
4770
exit -- we got all the server said it had
478
end if
4793
if not gotheader and match({13,10,13,10},data) then -- we got the header in there
4803
header = data[1..match({13,10,13,10},data)-1] -- split off the header
4813
data = data[match({13,10,13,10},data)+4..$] -- and the data is what's left, we keep using data in the sock loop
4823
parse_recvheader(header) -- sets up recvheader -- global var
4833
junk = get_recvheader("Content-Length")
4843
if not equal(junk,-1) then
4853
junk = val:value(junk[2])
4863
contentlen = junk[2]
4873
if equal(contentlen,0) then exit end if -- there's no more
4883
if equal(contentlen,length(data)) then exit end if -- there's no more
489
end if
4900
gotheader = 1 -- we got what we came for here
491
end if
492
entry
493
4943
junk2 = sock:select(sock, {}, {}, timeout) -- status check
495
-- Do we have readable data?
4963
if (length(junk2[1]) > 2) and equal(junk2[1][2],1) then
4973
last = time()
4983
junk = sock:receive(sock, 0) -- then recieve it
499
else
500
-- assume server has hung, abort
5010
exit
502
end if
5033
end while
504
else
5050
header = -1
5060
data = "could not send or recieve using socket"
507
end if -- if success -- sock:send
508
else
5090
header = -1
5100
data = "could not connect to socket"
511
end if -- if success = 1 then -- sock:connect
5123
if sock:close(sock) then end if
513
514
-- clear any POSTDATA
5153
set_sendheader("POSTDATA", "")
5163
set_sendheader("POST", "")
5173
set_sendheader("GET", "")
5183
set_sendheader("Content-Type", "")
5193
set_sendheader("Content-Length", "0")
5203
set_sendheader_default()
521
5223
return {header,data}
523
end function
524
525
--**
526
-- Works the same as [[:get_url]](), but maintains an internal
527
-- state register based on cookies received.
528
--
529
-- Warning:
530
-- This function is not yet implemented.
531
--
532
-- Parameters:
533
-- # ##inet_addr## : a sequence holding an address
534
-- # ##hostname## : a string, the name for the host
535
-- # ##file## : a file name to transmit
536
--
537
-- Returns:
538
-- A **sequence**, {header, body} on success, or an empty sequence on error.
539
--
540
-- Example 1:
541
--
542
-- addrinfo = getaddrinfo("www.yahoo.com","http",0)
543
-- if atom(addrinfo) or length(addrinfo) < 1 or
544
-- length(addrinfo[1]) < 5 then
545
-- puts(1,"Uh, oh")
546
-- return {}
547
-- else
548
-- inet_addr = addrinfo[1][5]
549
-- end if
550
-- data = get_http_use_cookie(inet_addr,"www.yahoo.com","")
551
--
552
--
553
-- See also:
554
-- [[:get_url]]
555
5560
557
/*
558
atom socket, success, last_data_len, cpos, offset
559
sequence header, header2, body, data, updata
560
sequence cookielist, request, cookie
561
object junk -- a general throwaway temp var
562
563
cookielist = {}
564
request = ""
565
-- cookie = {name,domain,path,expires,encrypted,version}
566
567
if length(inet_addr)=0 then
568
return {"",""}
569
end if
570
571
if length(file)=0 or file[1]!='/' then file = '/'&file end if
572
573
-- was the POSTDATA set?
574
junk = get_sendheader("POSTDATA")
575
if equal(junk[3],"") then
576
-- if no, assume it's a GET
577
set_sendheader("GET",file)
578
else
579
-- if so, then it's definitely a POST (err, or PUT, but we don't do PUT)
580
set_sendheader("POST",file)
581
end if
582
583
-- This is required for virtual shared hosting.
584
-- On dedicated boxes on fixed ip,
585
-- you can http to the ip, and GET/POST is enough to deal with it.
586
-- Setting it is safe, either way.
587
set_sendheader("HOST",hostname)
588
589
for ctr = 1 to length(this_cookiejar) do
590
if sequence(this_cookiejar[ctr]) and length(this_cookiejar[ctr])>=2 and
591
sequence(this_cookiejar[ctr][1]) and
592
(match(hostname,this_cookiejar[ctr][2])>0 or match(this_cookiejar[ctr][2],hostname)>0) and
593
(length(file)=0 or match(this_cookiejar[ctr][3],file)>0)
594
then
595
cookielist = append(cookielist,this_cookiejar[ctr])
596
end if
597
end for
598
599
-- TO DO: Sort cookielist by domain, path (longer path before shorter path)
600
-- request = sprintf("GET /%s HTTP/1.0\nHost: %s\n",{file,hostname})
601
for idx = 1 to length(cookielist) do
602
-- if idx = 1 then
603
-- request = request & "Cookie: "&cookielist[idx][1]
604
-- else
605
-- request = request & " "&cookielist[idx][1]
606
-- end if
607
request = request & cookielist[idx][1]
608
if length(cookielist[idx][3])>0 then
609
request = request & "; $Path=" & cookielist[idx][3]
610
end if
611
if idx < length(cookielist) then
612
--request = request & ";\n"
613
request = request & ";"
614
else
615
--request = request & "\n"
616
end if
617
end for
618
-- request = request & "\n"
619
set_sendheader("Cookie",request)
620
621
data = {}
622
last_data_len = 0
623
socket = sock:create(AF_INET,SOCK_STREAM,0)
624
success = sock:connect(AF_INET, socket,inet_addr)
625
if success = 0 then
626
-- success = sock:send(socket,request,0)
627
success = sock:send(socket,eunet_format_sendheader(),0)
628
-- } end version 1.3.0 modification
629
if success > 0 then
630
junk = sock:receive(sock, 0)
631
while sequence(junk) do
632
data = data & junk
633
if gotheader and equal(contentlen,length(data)) then
634
exit -- we got all the server said it had
635
end if
636
if not gotheader and match({13,10,13,10},data) then -- we got the header in there
637
header = data[1..match({13,10,13,10},data)-1] -- split off the header
638
data = data[match({13,10,13,10},data)+4..$] -- and the data is what's left, we keep using data in the sock loop
639
parse_recvheader(header) -- sets up recvheader -- global var
640
junk = get_recvheader("Content-Length")
641
if not equal(junk,-1) then
642
junk = val:value(junk[2])
643
contentlen = junk[2]
644
if equal(contentlen,0) then exit end if -- there's no more
645
if equal(contentlen,length(data)) then exit end if -- there's no more
646
end if
647
gotheader = 1 -- we got what we came for here
648
end if
649
junk = sock:receive(sock, 0)
650
end while
651
end if
652
end if
653
if close_socket(socket) then end if
654
655
656
header2 = header
657
cpos = match("SET-COOKIE",upper(header2)) -- this should be using get_recvheader() etc
658
while cpos > 0 do
659
header2 = header2[cpos+10 .. $]
660
data = header2
661
cpos = find(':',data)
662
if cpos > 0 then
663
data = data[cpos+1..$]
664
end if
665
offset = 0
666
cpos = match(13&10,data)
667
while cpos > 1 and data[offset+cpos-1]=';' do
668
offset = offset + cpos + 2
669
cpos = match(13&10,data[offset..$])
670
end while
671
offset = offset + cpos - 1
672
data = data[1..offset]
673
updata = upper(data)
674
cookie = {"","","","","N",""}
675
offset = match("PATH=",updata)
676
if offset > 0 then
677
cpos = find(';',data[offset .. $])
678
if cpos = 0 then cpos = length(data)-offset+2 end if
679
cookie[3] = data[offset+5..offset+cpos-2]
680
end if
681
cpos = find(';',data)
682
if cpos = 0 then cpos = length(data)+1 end if
683
cookie[1] = _socket_trim(data[1..cpos-1])
684
if cpos > length(data) then
685
data = ""
686
updata = ""
687
else
688
data = data[cpos+1 .. $]
689
updata = updata[cpos+1..length(data)]
690
end if
691
offset = match("DOMAIN=",updata)
692
if offset > 0 then
693
cpos = find(';',data[offset .. $])
694
if cpos = 0 then cpos = length(data)-offset+2 end if
695
cookie[2] = data[offset+7..offset+cpos-2]
696
-- Offset is base 1. If the semicolon is in the first position, cpos
697
-- is also 1. Since we don't want to include the semicolon, we need
698
-- to subtract 1 for offset's base and 1 to go to the char before
699
-- cpos, thus the subtracting of two. In the case of end of string
700
-- (cpos = 0), we need to add those two back to compensate for the
701
-- different scenario (+offset-offset = 0 and +2-2 = 0, therefore
702
-- cpos = length(data), which is what we want).
703
end if
704
offset = match("EXPIRES=",updata)
705
if offset > 0 then
706
cpos = find(';',data[offset .. $])
707
if cpos = 0 then cpos = length(data)-offset+2 end if
708
cookie[4] = data[offset+8..offset+cpos-2]
709
end if
710
offset = match("VERSION=",updata)
711
if offset > 0 then
712
cpos = find(';',data[offset..$])
713
if cpos = 0 then cpos = length(data)-offset+2 end if
714
cookie[6] = data[offset+8..offset+cpos-2]
715
end if
716
offset = match("MAX-AGE=",updata)
717
if offset > 0 then
718
cpos = find(';',data[offset..$])
719
if cpos = 0 then cpos = length(data)-offset+2 end if
720
cookie[4] = data[offset+8..offset+cpos-2]
721
end if
722
offset = match("SECURE",updata)
723
if offset > 0 then
724
cookie[5] = "Y"
725
end if
726
cpos = find('=',cookie[1])
727
if cpos > 0 then
728
request = cookie[1][1..cpos]
729
else
730
request = "="
731
end if
732
cpos = 0
733
for ctr = 1 to length(this_cookiejar) do
734
if sequence(this_cookiejar[ctr]) and length(this_cookiejar[ctr])>=2 and
735
match(cookie[1],this_cookiejar[ctr][1])>0 and
736
eu:compare(cookie[2],this_cookiejar[ctr][2])=0 and
737
eu:compare(this_cookiejar[ctr][3],cookie[3])=0 then
738
this_cookiejar[ctr] = cookie
739
cpos = ctr
740
exit
741
end if
742
end for
743
if cpos = 0 then
744
this_cookiejar = append(this_cookiejar,cookie)
745
end if
746
cpos = match("SET-COOKIE",upper(header2))
747
end while
748
749
-- clear any POSTDATA
750
set_sendheader("POSTDATA", "")
751
set_sendheader("POST", "")
752
set_sendheader("GET", "")
753
set_sendheader("Content-Type", "")
754
set_sendheader("Content-Length", "0")
755
set_sendheader_default()
756
757
return {header,body}
758
*/
7590
return -1
760
end function
761
762
--**
763
-- Returns data from an http internet site.
764
--
765
-- Parameters:
766
-- # ##url##: URL to access
767
-- # ##post_data##: Optional post data
768
--
769
-- Returns:
770
-- A **sequence** {header, body} on success, or an empty sequence on error.
771
--
772
-- Comments:
773
-- If ##post_data## is empty, then a normal GET request is done. If ##post_data## is non-empty
774
-- then ##get_url## will perform a POST request and supply ##post_data## during the request.
775
--
776
-- Example 1:
777
--
778
-- url = "http://banners.wunderground.com/weathersticker/mini" &
779
-- "Weather2_metric_cond/language/www/US/PA/Philadelphia.gif"
780
--
781
-- temp = get_url(url)
782
-- if length(temp)>=2 and length(temp[2])>0 then
783
-- tempfp = open(TEMPDIR&"current_weather.gif","wb")
784
-- puts(tempfp,temp[2])
785
-- close(tempfp)
786
-- end if
787
--
788
7893
790
object addrinfo, url_data
791
7923
url_data = parse(url)
7933
if atom(url_data) then return 0 end if
794
7953
addrinfo = host_by_name(url_data[URL_HOSTNAME])
7963
if atom(addrinfo) or length(addrinfo) < 3 or length(addrinfo[3]) = 0 then
7970
return 0
798
end if
799
8003
set_sendheader("POSTDATA", post_data)
801
8023
if url_data[URL_PORT] = 0 then
803
-- url didn't specify a port, so default to 80
8042
url_data[URL_PORT] = 80
805
end if
806
8073
sequence data = {"",""}
8083
if eu:compare(lower(url_data[URL_PROTOCOL]),"http") = 0 then
8093
data = get_http(addrinfo[3][1], url_data[URL_HOSTNAME],
810
url_data[URL_PATH] & url_data[URL_QUERY_STRING], , url_data[URL_PORT])
811
end if
812
8133
return data
814
end function
815
816
-- set the lines in the "proper" order for sending, not that the defaults will get sent.
8171
set_sendheader_default()
818