Subversion Repositories Kolibri OS

Rev

Rev 4221 | Rev 4233 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4158 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  HTTP library for KolibriOS                                     ;;
7
;;                                                                 ;;
8
;;   Written by hidnplayr@kolibrios.org                            ;;
9
;;                                                                 ;;
10
;;         GNU GENERAL PUBLIC LICENSE                              ;;
11
;;          Version 2, June 1991                                   ;;
12
;;                                                                 ;;
13
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14
 
15
; references:
16
; "HTTP made really easy", http://www.jmarshall.com/easy/http/
17
; "Hypertext Transfer Protocol -- HTTP/1.1", http://tools.ietf.org/html/rfc2616
18
 
19
 
20
        URLMAXLEN       = 65535
21
        BUFFERSIZE      = 4096
4206 hidnplayr 22
        TIMEOUT         = 1000  ; in 1/100 s
4158 hidnplayr 23
 
24
        __DEBUG__       = 1
25
        __DEBUG_LEVEL__ = 1
26
 
27
 
28
format MS COFF
29
 
30
public @EXPORT as 'EXPORTS'
31
 
32
include '../../../struct.inc'
33
include '../../../proc32.inc'
34
include '../../../macros.inc'
35
purge section,mov,add,sub
36
include '../../../debug-fdo.inc'
37
 
38
include '../../../network.inc'
39
include 'http.inc'
40
 
41
virtual at 0
42
        http_msg http_msg
43
end virtual
44
 
45
macro copy_till_zero {
46
  @@:
47
        lodsb
48
        test    al, al
49
        jz      @f
50
        stosb
51
        jmp     @r
52
  @@:
53
}
54
 
4167 hidnplayr 55
macro HTTP_init_buffer buffer, socketnum {
56
 
57
        mov     eax, buffer
58
        push    socketnum
59
        popd    [eax + http_msg.socket]
60
        lea     esi, [eax + http_msg.data]
4205 hidnplayr 61
        mov     [eax + http_msg.flags], FLAG_CONNECTED
4167 hidnplayr 62
        mov     [eax + http_msg.write_ptr], esi
63
        mov     [eax + http_msg.buffer_length], BUFFERSIZE -  http_msg.data
64
        mov     [eax + http_msg.chunk_ptr], 0
65
 
66
        mov     [eax + http_msg.status], 0
67
        mov     [eax + http_msg.header_length], 0
68
        mov     [eax + http_msg.content_length], 0
4168 hidnplayr 69
        mov     [eax + http_msg.content_received], 0
4206 hidnplayr 70
 
71
        push    eax ebp
72
        mov     ebp, eax
73
        mcall   29, 9
74
        mov     [ebp + http_msg.timestamp], eax
75
        pop     ebp eax
4167 hidnplayr 76
}
77
 
4158 hidnplayr 78
section '.flat' code readable align 16
79
 
80
;;===========================================================================;;
81
lib_init: ;//////////////////////////////////////////////////////////////////;;
82
;;---------------------------------------------------------------------------;;
83
;? Library entry point (called after library load)                           ;;
84
;;---------------------------------------------------------------------------;;
85
;> eax = pointer to memory allocation routine                                ;;
86
;> ebx = pointer to memory freeing routine                                   ;;
87
;> ecx = pointer to memory reallocation routine                              ;;
88
;> edx = pointer to library loading routine                                  ;;
89
;;---------------------------------------------------------------------------;;
4209 hidnplayr 90
;< eax = 1 (fail) / 0 (ok)                                                   ;;
4158 hidnplayr 91
;;===========================================================================;;
92
        mov     [mem.alloc], eax
93
        mov     [mem.free], ebx
94
        mov     [mem.realloc], ecx
95
        mov     [dll.load], edx
96
 
97
        invoke  dll.load, @IMPORT
4209 hidnplayr 98
        test    eax, eax
99
        jnz     .error
4158 hidnplayr 100
 
101
; load proxy settings
4216 hidnplayr 102
        pusha
4158 hidnplayr 103
        invoke  ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
104
        invoke  ini.get_int, inifile, sec_proxy, key_proxyport, 80
105
        mov     [proxyPort], eax
106
        invoke  ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
107
        invoke  ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
4216 hidnplayr 108
        popa
4158 hidnplayr 109
 
4212 hidnplayr 110
        DEBUGF  1, "HTTP library: init OK\n"
4211 hidnplayr 111
 
4158 hidnplayr 112
        xor     eax, eax
113
        ret
114
 
4209 hidnplayr 115
  .error:
4212 hidnplayr 116
        DEBUGF  1, "ERROR loading libraries\n"
4211 hidnplayr 117
 
4158 hidnplayr 118
        xor     eax, eax
4209 hidnplayr 119
        inc     eax
120
 
4158 hidnplayr 121
        ret
122
 
123
 
124
 
125
 
126
;;================================================================================================;;
4221 hidnplayr 127
proc HTTP_get URL, add_header ;///////////////////////////////////////////////////////////////////;;
4158 hidnplayr 128
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 129
;? Initiates a HTTP connection, using 'GET' method.                                               ;;
4158 hidnplayr 130
;;------------------------------------------------------------------------------------------------;;
4221 hidnplayr 131
;> URL          = pointer to ASCIIZ URL                                                           ;;
132
;> add_header   = pointer to additional header parameters (ASCIIZ), or null for none.             ;;
4158 hidnplayr 133
;;------------------------------------------------------------------------------------------------;;
134
;< eax = 0 (error) / buffer ptr                                                                   ;;
135
;;================================================================================================;;
136
locals
137
        hostname        dd ?
138
        pageaddr        dd ?
139
        sockaddr        dd ?
140
        socketnum       dd ?
141
        buffer          dd ?
4167 hidnplayr 142
        port            dd ?
4158 hidnplayr 143
endl
144
 
4216 hidnplayr 145
        pusha
146
 
4158 hidnplayr 147
; split the URL into hostname and pageaddr
148
        stdcall parse_url, [URL]
149
        test    eax, eax
150
        jz      .error
151
        mov     [hostname], eax
152
        mov     [pageaddr], ebx
4221 hidnplayr 153
        mov     [port], ecx
4158 hidnplayr 154
 
155
; Do we need to use a proxy?
156
        cmp     [proxyAddr], 0
157
        jne     .proxy_done
158
 
159
  .proxy_done:
160
 
4167 hidnplayr 161
;;;;
162
 
163
; Connect to the other side.
164
        stdcall open_connection, [hostname], [port]
4158 hidnplayr 165
        test    eax, eax
4167 hidnplayr 166
        jz      .error
167
        mov     [socketnum], eax
4158 hidnplayr 168
 
4167 hidnplayr 169
; Create the HTTP request.
170
        invoke  mem.alloc, BUFFERSIZE
4158 hidnplayr 171
        test    eax, eax
172
        jz      .error
4167 hidnplayr 173
        mov     [buffer], eax
174
        mov     edi, eax
175
        DEBUGF  1, "Buffer has been allocated.\n"
4158 hidnplayr 176
 
4167 hidnplayr 177
        mov     esi, str_get
178
        copy_till_zero
4158 hidnplayr 179
 
4167 hidnplayr 180
        mov     esi, [pageaddr]
181
        copy_till_zero
4158 hidnplayr 182
 
4167 hidnplayr 183
        mov     esi, str_http11
184
        mov     ecx, str_http11.length
185
        rep     movsb
186
 
187
        mov     esi, [hostname]
188
        copy_till_zero
189
 
4221 hidnplayr 190
        mov     esi, [add_header]
191
        test    esi, esi
192
        jz      @f
193
        copy_till_zero
194
  @@:
195
 
4167 hidnplayr 196
        mov     esi, str_close
197
        mov     ecx, str_close.length
198
        rep     movsb
199
 
200
        mov     byte[edi], 0
201
        DEBUGF  1, "Request:\n%s", [buffer]
202
 
4222 hidnplayr 203
; Free unused memory
204
        push    edi
205
        invoke  mem.free, [pageaddr]
206
        invoke  mem.free, [hostname]
207
        pop     esi
208
 
4167 hidnplayr 209
; Send the request
210
        sub     esi, [buffer]   ; length
211
        xor     edi, edi        ; flags
212
        mcall   send, [socketnum], [buffer]
4158 hidnplayr 213
        test    eax, eax
214
        jz      .error
4167 hidnplayr 215
        DEBUGF  1, "Request has been sent to server.\n"
4158 hidnplayr 216
 
4167 hidnplayr 217
        HTTP_init_buffer [buffer], [socketnum]
218
 
4216 hidnplayr 219
        popa
220
        mov     eax, [buffer]   ; return buffer ptr
221
        ret
4167 hidnplayr 222
 
223
  .error:
224
        DEBUGF  1, "Error!\n"
4216 hidnplayr 225
        popa
4167 hidnplayr 226
        xor     eax, eax        ; return 0 = error
227
        ret
228
 
229
endp
230
 
231
 
232
 
233
;;================================================================================================;;
4221 hidnplayr 234
proc HTTP_head URL, add_header ;//////////////////////////////////////////////////////////////////;;
4167 hidnplayr 235
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 236
;? Initiates a HTTP connection, using 'HEAD' method.                                              ;;
4167 hidnplayr 237
;;------------------------------------------------------------------------------------------------;;
4221 hidnplayr 238
;> URL          = pointer to ASCIIZ URL                                                           ;;
239
;> add_header   = pointer to additional header parameters (ASCIIZ), or null for none.             ;;
4167 hidnplayr 240
;;------------------------------------------------------------------------------------------------;;
241
;< eax = 0 (error) / buffer ptr                                                                   ;;
242
;;================================================================================================;;
243
locals
244
        hostname        dd ?
245
        pageaddr        dd ?
246
        sockaddr        dd ?
247
        socketnum       dd ?
248
        buffer          dd ?
249
        port            dd ?
250
endl
251
 
4216 hidnplayr 252
        pusha
4167 hidnplayr 253
; split the URL into hostname and pageaddr
254
        stdcall parse_url, [URL]
4158 hidnplayr 255
        test    eax, eax
4167 hidnplayr 256
        jz      .error
257
        mov     [hostname], eax
258
        mov     [pageaddr], ebx
4221 hidnplayr 259
        mov     [port], ecx
4158 hidnplayr 260
 
4167 hidnplayr 261
; Do we need to use a proxy?
262
        cmp     [proxyAddr], 0
263
        jne     .proxy_done
4158 hidnplayr 264
 
4167 hidnplayr 265
        ; TODO: set hostname to that of the
266
  .proxy_done:
267
 
268
;;;;
269
 
270
; Connect to the other side.
271
        stdcall open_connection, [hostname], [port]
272
        test    eax, eax
273
        jz      .error
274
        mov     [socketnum], eax
275
 
4158 hidnplayr 276
; Create the HTTP request.
277
        invoke  mem.alloc, BUFFERSIZE
278
        test    eax, eax
279
        jz      .error
280
        mov     [buffer], eax
4167 hidnplayr 281
        mov     edi, eax
4158 hidnplayr 282
        DEBUGF  1, "Buffer has been allocated.\n"
283
 
4167 hidnplayr 284
        mov     esi, str_head
4158 hidnplayr 285
        copy_till_zero
286
 
4167 hidnplayr 287
        mov     esi, [pageaddr]
288
        copy_till_zero
289
 
4158 hidnplayr 290
        mov     esi, str_http11
291
        mov     ecx, str_http11.length
292
        rep     movsb
293
 
294
        mov     esi, [hostname]
295
        copy_till_zero
296
 
4221 hidnplayr 297
        mov     esi, [add_header]
298
        test    esi, esi
299
        jz      @f
300
        copy_till_zero
301
  @@:
302
 
4158 hidnplayr 303
        mov     esi, str_close
304
        mov     ecx, str_close.length
305
        rep     movsb
306
 
307
        mov     byte[edi], 0
308
        DEBUGF  1, "Request:\n%s", [buffer]
309
 
4222 hidnplayr 310
 
311
; Free unused memory
312
        push    edi
313
        invoke  mem.free, [pageaddr]
314
        invoke  mem.free, [hostname]
315
        pop     esi
316
 
4167 hidnplayr 317
; Send the request
4158 hidnplayr 318
        sub     esi, [buffer]   ; length
319
        xor     edi, edi        ; flags
320
        mcall   send, [socketnum], [buffer]
321
        test    eax, eax
322
        jz      .error
323
        DEBUGF  1, "Request has been sent to server.\n"
324
 
4167 hidnplayr 325
        HTTP_init_buffer [buffer], [socketnum]
4158 hidnplayr 326
 
4216 hidnplayr 327
        popa
328
        mov     eax, [buffer]
4167 hidnplayr 329
        ret                     ; return buffer ptr
4158 hidnplayr 330
 
4167 hidnplayr 331
  .error:
332
        DEBUGF  1, "Error!\n"
4216 hidnplayr 333
        popa
4167 hidnplayr 334
        xor     eax, eax        ; return 0 = error
335
        ret
336
 
337
endp
338
 
339
 
340
;;================================================================================================;;
4221 hidnplayr 341
proc HTTP_post URL, add_header, content_type, content_length ;////////////////////////////////////;;
4167 hidnplayr 342
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 343
;? Initiates a HTTP connection, using 'GET' method.                                               ;;
4167 hidnplayr 344
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 345
;> URL                  = pointer to ASCIIZ URL                                                   ;;
4221 hidnplayr 346
;> add_header           = pointer to additional header parameters (ASCIIZ), or null for none.     ;;
4202 hidnplayr 347
;> content_type         = pointer to ASCIIZ string containing content type                        ;;
348
;> content_length       = length of content (in bytes)                                            ;;
4167 hidnplayr 349
;;------------------------------------------------------------------------------------------------;;
350
;< eax = 0 (error) / buffer ptr                                                                   ;;
351
;;================================================================================================;;
352
locals
353
        hostname        dd ?
354
        pageaddr        dd ?
355
        sockaddr        dd ?
356
        socketnum       dd ?
357
        buffer          dd ?
358
        port            dd ?
359
endl
360
 
4216 hidnplayr 361
        pusha
4167 hidnplayr 362
; split the URL into hostname and pageaddr
363
        stdcall parse_url, [URL]
364
        test    eax, eax
365
        jz      .error
366
        mov     [hostname], eax
367
        mov     [pageaddr], ebx
4221 hidnplayr 368
        mov     [port], ecx
4167 hidnplayr 369
 
370
; Do we need to use a proxy?
371
        cmp     [proxyAddr], 0
372
        jne     .proxy_done
373
 
374
        ; TODO: set hostname to that of the
375
  .proxy_done:
376
 
377
;;;;
378
 
379
; Connect to the other side.
380
        stdcall open_connection, [hostname], [port]
381
        test    eax, eax
382
        jz      .error
383
        mov     [socketnum], eax
384
 
385
; Create the HTTP request.
386
        invoke  mem.alloc, BUFFERSIZE
387
        test    eax, eax
388
        jz      .error
389
        mov     [buffer], eax
390
        mov     edi, eax
391
        DEBUGF  1, "Buffer has been allocated.\n"
392
 
393
        mov     esi, str_post
394
        copy_till_zero
395
 
396
        mov     esi, [pageaddr]
397
        copy_till_zero
398
 
399
        mov     esi, str_http11
400
        mov     ecx, str_http11.length
401
        rep     movsb
402
 
403
        mov     esi, [hostname]
404
        copy_till_zero
405
 
406
        mov     esi, str_post_cl
407
        mov     ecx, str_post_cl.length
408
        rep     movsb
409
 
410
        mov     eax, [content_length]
411
        call    ascii_dec
412
 
413
        mov     esi, str_post_ct
414
        mov     ecx, str_post_ct.length
415
        rep     movsb
416
 
417
        mov     esi, [content_type]
4221 hidnplayr 418
        copy_till_zero
4167 hidnplayr 419
 
4221 hidnplayr 420
        mov     esi, [add_header]
421
        test    esi, esi
422
        jz      @f
423
        copy_till_zero
424
  @@:
425
 
4167 hidnplayr 426
        mov     esi, str_close
427
        mov     ecx, str_close.length
428
        rep     movsb
429
 
430
        mov     byte[edi], 0
431
        DEBUGF  1, "Request:\n%s", [buffer]
432
 
4222 hidnplayr 433
; Free unused memory
434
        push    edi
435
        invoke  mem.free, [pageaddr]
436
        invoke  mem.free, [hostname]
437
        pop     esi
438
 
4167 hidnplayr 439
; Send the request
440
        sub     esi, [buffer]   ; length
441
        xor     edi, edi        ; flags
442
        mcall   send, [socketnum], [buffer]
443
        test    eax, eax
444
        jz      .error
445
        DEBUGF  1, "Request has been sent to server.\n"
446
 
447
        HTTP_init_buffer [buffer], [socketnum]
4206 hidnplayr 448
 
4216 hidnplayr 449
        popa
450
        mov     eax, [buffer]
4158 hidnplayr 451
        ret                     ; return buffer ptr
452
 
453
  .error:
454
        DEBUGF  1, "Error!\n"
4216 hidnplayr 455
        popa
4158 hidnplayr 456
        xor     eax, eax        ; return 0 = error
457
        ret
458
 
459
endp
460
 
461
 
462
 
463
;;================================================================================================;;
464
proc HTTP_process identifier ;////////////////////////////////////////////////////////////////////;;
465
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 466
;? Receive data from the server, parse headers and put data in receive buffer.                    ;;
467
;? To complete a transfer, this procedure must be called over and over again untill it returns 0. ;;
4158 hidnplayr 468
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 469
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
4158 hidnplayr 470
;;------------------------------------------------------------------------------------------------;;
471
;< eax = -1 (not finished) / 0 finished                                                           ;;
472
;;================================================================================================;;
473
        pusha
474
        mov     ebp, [identifier]
4162 hidnplayr 475
 
4209 hidnplayr 476
; If the connection is closed, return immediately
4205 hidnplayr 477
        test    [ebp + http_msg.flags], FLAG_CONNECTED
478
        jz      .connection_closed
479
 
4162 hidnplayr 480
; Receive some data
4158 hidnplayr 481
        mcall   recv, [ebp + http_msg.socket], [ebp + http_msg.write_ptr], \
482
                      [ebp + http_msg.buffer_length], MSG_DONTWAIT
483
        cmp     eax, 0xffffffff
484
        je      .check_socket
4220 hidnplayr 485
 
486
        test    eax, eax
487
        jz      .server_closed
4158 hidnplayr 488
        DEBUGF  1, "Received %u bytes\n", eax
489
 
4209 hidnplayr 490
; Update timestamp
4206 hidnplayr 491
        push    eax
492
        mcall   29, 9
493
        mov     [ebp + http_msg.timestamp], eax
494
        pop     eax
495
 
4162 hidnplayr 496
; Update pointers
4158 hidnplayr 497
        mov     edi, [ebp + http_msg.write_ptr]
498
        add     [ebp + http_msg.write_ptr], eax
499
        sub     [ebp + http_msg.buffer_length], eax
500
        jz      .got_all_data
4162 hidnplayr 501
 
502
; If data is chunked, combine chunks into contiguous data.
503
        test    [ebp + http_msg.flags], FLAG_CHUNKED
504
        jnz     .chunk_loop
505
 
4212 hidnplayr 506
; Did we detect the (final) header yet?
4158 hidnplayr 507
        test    [ebp + http_msg.flags], FLAG_GOT_HEADER
508
        jnz     .header_parsed
509
 
4212 hidnplayr 510
; We havent found the (final) header yet, search for it..
511
  .scan_again:
512
        ; eax = total number of bytes received so far
513
        mov     eax, [ebp + http_msg.write_ptr]
514
        sub     eax, http_msg.data
515
        sub     eax, ebp
516
        sub     eax, [ebp + http_msg.header_length]
517
        ; edi is ptr to begin of header
518
        lea     edi, [ebp + http_msg.data]
519
        add     edi, [ebp + http_msg.header_length]
520
        ; put it in esi for next proc too
521
        mov     esi, edi
522
        sub     eax, 3
523
        jle     .need_more_data
524
  .scan_loop:
4158 hidnplayr 525
        ; scan for end of header (empty line)
526
        cmp     dword[edi], 0x0a0d0a0d                  ; end of header
527
        je      .end_of_header
4212 hidnplayr 528
        cmp     word[edi+2], 0x0a0a                     ; notice the use of offset + 2, to calculate header length correctly :)
4158 hidnplayr 529
        je      .end_of_header
530
        inc     edi
531
        dec     eax
4212 hidnplayr 532
        jnz     .scan_loop
533
        jmp     .need_more_data
4158 hidnplayr 534
 
535
  .end_of_header:
536
        add     edi, 4 - http_msg.data
537
        sub     edi, ebp
4212 hidnplayr 538
        mov     [ebp + http_msg.header_length], edi     ; If this isnt the final header, we'll use this as an offset to find real header.
4158 hidnplayr 539
        DEBUGF  1, "Header length: %u\n", edi
540
 
541
; Ok, we have found header:
4212 hidnplayr 542
        cmp     dword[esi], 'HTTP'
4158 hidnplayr 543
        jne     .invalid_header
4212 hidnplayr 544
        cmp     dword[esi+4], '/1.0'
4158 hidnplayr 545
        je      .http_1.0
4212 hidnplayr 546
        cmp     dword[esi+4], '/1.1'
4158 hidnplayr 547
        jne     .invalid_header
548
        or      [ebp + http_msg.flags], FLAG_HTTP11
549
  .http_1.0:
4212 hidnplayr 550
        cmp     byte[esi+8], ' '
4158 hidnplayr 551
        jne     .invalid_header
552
 
4212 hidnplayr 553
        add     esi, 9
4158 hidnplayr 554
        xor     eax, eax
555
        xor     ebx, ebx
556
        mov     ecx, 3
557
  .statusloop:
558
        lodsb
559
        sub     al, '0'
560
        jb      .invalid_header
561
        cmp     al, 9
562
        ja      .invalid_header
563
        lea     ebx, [ebx + 4*ebx]
564
        shl     ebx, 1
565
        add     ebx, eax
566
        dec     ecx
567
        jnz     .statusloop
4212 hidnplayr 568
 
569
; Ignore "100 - Continue" headers
570
        cmp     ebx, 100
571
        je      .scan_again
572
 
573
        DEBUGF  1, "Status: %u\n", ebx
4158 hidnplayr 574
        mov     [ebp + http_msg.status], ebx
4212 hidnplayr 575
        or      [ebp + http_msg.flags], FLAG_GOT_HEADER
4158 hidnplayr 576
 
577
; Now, convert all header names to lowercase.
578
; This way, it will be much easier to find certain header fields, later on.
579
 
580
        lea     esi, [ebp + http_msg.data]
581
        mov     ecx, [ebp + http_msg.header_length]
582
  .need_newline:
583
        inc     esi
584
        dec     ecx
585
        jz      .convert_done
586
        cmp     byte[esi], 10
587
        jne     .need_newline
588
; Ok, we have a newline, a line beginning with space or tabs has no header fields.
589
 
590
        inc     esi
591
        dec     ecx
592
        jz      .convert_done
593
        cmp     byte[esi], ' '
594
        je      .need_newline
595
        cmp     byte[esi], 9    ; horizontal tab
596
        je      .need_newline
597
        jmp     .convert_loop
598
  .next_char:
599
        inc     esi
600
        dec     ecx
601
        jz      .convert_done
602
  .convert_loop:
603
        cmp     byte[esi], ':'
604
        je      .need_newline
605
        cmp     byte[esi], 'A'
606
        jb      .next_char
607
        cmp     byte[esi], 'Z'
608
        ja      .next_char
609
        or      byte[esi], 0x20 ; convert to lowercase
610
        jmp     .next_char
611
  .convert_done:
612
        mov     byte[esi-1], 0
613
        lea     esi, [ebp + http_msg.data]
614
        DEBUGF  1, "Header names converted to lowercase:\n%s\n", esi
615
 
616
; Check for content-length header field.
4222 hidnplayr 617
        stdcall HTTP_find_header_field, ebp, str_cl
4158 hidnplayr 618
        test    eax, eax
619
        jz      .no_content
620
        or      [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
621
 
622
        xor     edx, edx
623
  .cl_loop:
624
        movzx   ebx, byte[eax]
625
        inc     eax
626
        cmp     bl, 10
627
        je      .cl_ok
628
        cmp     bl, 13
629
        je      .cl_ok
630
        cmp     bl, ' '
631
        je      .cl_ok
632
        sub     bl, '0'
633
        jb      .invalid_header
634
        cmp     bl, 9
635
        ja      .invalid_header
636
        lea     edx, [edx + edx*4]      ; edx = edx*10
637
        shl     edx, 1                  ;
638
        add     edx, ebx
639
        jmp     .cl_loop
640
 
641
  .cl_ok:
642
        mov     [ebp + http_msg.content_length], edx
643
        DEBUGF  1, "Content-length: %u\n", edx
644
 
645
; Resize buffer according to content-length.
4168 hidnplayr 646
        add     edx, [ebp + http_msg.header_length]
647
        add     edx, http_msg.data
4158 hidnplayr 648
 
4168 hidnplayr 649
        mov     ecx, edx
4158 hidnplayr 650
        sub     ecx, [ebp + http_msg.write_ptr]
651
        mov     [ebp + http_msg.buffer_length], ecx
652
 
4168 hidnplayr 653
        invoke  mem.realloc, ebp, edx
4158 hidnplayr 654
        or      eax, eax
4212 hidnplayr 655
        jz      .no_ram
4203 hidnplayr 656
 
4220 hidnplayr 657
  .not_chunked:
4212 hidnplayr 658
        mov     eax, [ebp + http_msg.write_ptr]
4168 hidnplayr 659
        sub     eax, [ebp + http_msg.header_length]
4212 hidnplayr 660
        sub     eax, http_msg.data
661
        sub     eax, ebp
4158 hidnplayr 662
        jmp     .header_parsed  ; hooray!
663
 
664
  .no_content:
665
        DEBUGF  1, "Content-length not found.\n"
666
 
667
; We didnt find 'content-length', maybe server is using chunked transfer encoding?
668
; Try to find 'transfer-encoding' header.
4222 hidnplayr 669
        stdcall HTTP_find_header_field, ebp, str_te
4158 hidnplayr 670
        test    eax, eax
4220 hidnplayr 671
        jz      .not_chunked
4158 hidnplayr 672
 
673
        mov     ebx, dword[eax]
4162 hidnplayr 674
        or      ebx, 0x20202020
4158 hidnplayr 675
        cmp     ebx, 'chun'
4220 hidnplayr 676
        jne     .not_chunked
4158 hidnplayr 677
        mov     ebx, dword[eax+4]
4162 hidnplayr 678
        or      ebx, 0x00202020
679
        and     ebx, 0x00ffffff
4158 hidnplayr 680
        cmp     ebx, 'ked'
4220 hidnplayr 681
        jne     .not_chunked
4158 hidnplayr 682
 
683
        or      [ebp + http_msg.flags], FLAG_CHUNKED
684
        DEBUGF  1, "Transfer type is: chunked\n"
685
 
686
; Set chunk pointer where first chunk should begin.
4162 hidnplayr 687
        lea     eax, [ebp + http_msg.data]
688
        add     eax, [ebp + http_msg.header_length]
4158 hidnplayr 689
        mov     [ebp + http_msg.chunk_ptr], eax
690
 
4162 hidnplayr 691
  .chunk_loop:
4158 hidnplayr 692
        mov     ecx, [ebp + http_msg.write_ptr]
693
        sub     ecx, [ebp + http_msg.chunk_ptr]
4202 hidnplayr 694
        jb      .need_more_data_chunked         ; TODO: use this ecx !!!
4158 hidnplayr 695
 
4202 hidnplayr 696
; Chunkline starts here, convert the ASCII hex number into ebx
4158 hidnplayr 697
        mov     esi, [ebp + http_msg.chunk_ptr]
698
        xor     ebx, ebx
699
  .chunk_hexloop:
700
        lodsb
701
        sub     al, '0'
702
        jb      .chunk_
703
        cmp     al, 9
704
        jbe     .chunk_hex
4162 hidnplayr 705
        sub     al, 'A' - '0' - 10
4158 hidnplayr 706
        jb      .chunk_
4162 hidnplayr 707
        cmp     al, 15
4158 hidnplayr 708
        jbe     .chunk_hex
709
        sub     al, 'a' - 'A'
4162 hidnplayr 710
        cmp     al, 15
4158 hidnplayr 711
        ja      .chunk_
712
  .chunk_hex:
713
        shl     ebx, 4
714
        add     bl, al
715
        jmp     .chunk_hexloop
716
  .chunk_:
717
        DEBUGF  1, "got chunk of %u bytes\n", ebx
4202 hidnplayr 718
;;        cmp     esi, [ebp + http_msg.chunk_ptr]
719
;;        je
4158 hidnplayr 720
; If chunk size is 0, all chunks have been received.
721
        test    ebx, ebx
4162 hidnplayr 722
        jz      .got_all_data_chunked           ; last chunk, hooray! FIXME: what if it wasnt a valid hex number???
4158 hidnplayr 723
 
724
; Chunkline ends with a CR, LF or simply LF
4202 hidnplayr 725
  .end_of_chunkline?:
4158 hidnplayr 726
        cmp     al, 10
727
        je      .end_of_chunkline
728
        lodsb
4202 hidnplayr 729
        cmp     edi, [ebp + http_msg.write_ptr]
730
        jb      .end_of_chunkline?
731
        jmp     .need_more_data
4158 hidnplayr 732
 
733
  .end_of_chunkline:
4202 hidnplayr 734
; Update chunk ptr, and remember old one
735
        mov     edi, [ebp + http_msg.chunk_ptr]
736
        add     [ebp + http_msg.chunk_ptr], ebx
4162 hidnplayr 737
; Realloc buffer, make it 'chunksize' bigger.
738
        mov     eax, [ebp + http_msg.buffer_length]
739
        add     eax, ebx
740
        invoke  mem.realloc, ebp, eax
741
        or      eax, eax
742
        jz      .no_ram
743
        add     [ebp + http_msg.buffer_length], ebx
744
 
745
; Update write ptr
746
        mov     eax, esi
747
        sub     eax, edi
748
        sub     [ebp + http_msg.write_ptr], eax
749
 
4158 hidnplayr 750
; Now move all received data to the left (remove chunk header).
4162 hidnplayr 751
; Update content_length accordingly.
4158 hidnplayr 752
        mov     ecx, [ebp + http_msg.write_ptr]
753
        sub     ecx, esi
4168 hidnplayr 754
        add     [ebp + http_msg.content_received], ecx
4158 hidnplayr 755
        rep     movsb
4162 hidnplayr 756
        jmp     .chunk_loop
4158 hidnplayr 757
 
758
; Check if we got all the data.
4162 hidnplayr 759
  .header_parsed:
4168 hidnplayr 760
        add     [ebp + http_msg.content_received], eax
4220 hidnplayr 761
        test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
762
        jz      .need_more_data_and_space
4217 hidnplayr 763
        mov     eax, [ebp + http_msg.content_received]
764
        cmp     eax, [ebp + http_msg.content_length]
4168 hidnplayr 765
        jae     .got_all_data
4220 hidnplayr 766
        jmp     .need_more_data
4212 hidnplayr 767
 
4220 hidnplayr 768
  .need_more_data_and_space:
769
        mov     eax, [ebp + http_msg.write_ptr]
770
        add     eax, BUFFERSIZE
771
        sub     eax, ebp
772
        invoke  mem.realloc, ebp, eax
773
        or      eax, eax
774
        jz      .no_ram
775
        mov     [ebp + http_msg.buffer_length], BUFFERSIZE
776
 
4162 hidnplayr 777
  .need_more_data:
778
        popa
779
        xor     eax, eax
780
        dec     eax
781
        ret
4158 hidnplayr 782
 
4162 hidnplayr 783
  .need_more_data_chunked:
4168 hidnplayr 784
        add     [ebp + http_msg.content_received], eax
4158 hidnplayr 785
        popa
786
        xor     eax, eax
787
        dec     eax
788
        ret
789
 
4162 hidnplayr 790
  .got_all_data_chunked:
791
        mov     eax, [ebp + http_msg.chunk_ptr]
792
        sub     eax, [ebp + http_msg.header_length]
793
        sub     eax, http_msg.data
794
        sub     eax, ebp
795
        mov     [ebp + http_msg.content_length], eax
4168 hidnplayr 796
        mov     [ebp + http_msg.content_received], eax
4158 hidnplayr 797
  .got_all_data:
4217 hidnplayr 798
        DEBUGF  1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_received]
4205 hidnplayr 799
        or      [ebp + http_msg.flags], FLAG_GOT_ALL_DATA
800
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
4158 hidnplayr 801
        mcall   close, [ebp + http_msg.socket]
802
        popa
803
        xor     eax, eax
804
        ret
805
 
806
  .check_socket:
807
        cmp     ebx, EWOULDBLOCK
4206 hidnplayr 808
        jne     .socket_error
4158 hidnplayr 809
 
4206 hidnplayr 810
        mcall   29, 9
811
        sub     eax, TIMEOUT
812
        cmp     eax, [ebp + http_msg.timestamp]
4207 hidnplayr 813
        jb      .need_more_data
4206 hidnplayr 814
        DEBUGF  1, "ERROR: timeout\n"
815
        or      [ebp + http_msg.flags], FLAG_TIMEOUT_ERROR
816
        jmp     .disconnect
4158 hidnplayr 817
 
4220 hidnplayr 818
  .server_closed:
819
        DEBUGF  1, "server closed connection, transfer complete?\n"
820
        test    [ebp + http_msg.flags], FLAG_GOT_HEADER
821
        jz      .server_error
822
        test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
823
        jz      .got_all_data
824
 
825
  .server_error:
826
        pop     eax
827
        DEBUGF  1, "ERROR: server closed connection unexpectedly\n"
828
        or      [ebp + http_msg.flags], FLAG_TRANSFER_FAILED
829
        jmp     .disconnect
830
 
4158 hidnplayr 831
  .invalid_header:
4203 hidnplayr 832
        pop     eax
4158 hidnplayr 833
        DEBUGF  1, "ERROR: invalid header\n"
834
        or      [ebp + http_msg.flags], FLAG_INVALID_HEADER
4206 hidnplayr 835
        jmp     .disconnect
4158 hidnplayr 836
 
837
  .no_ram:
838
        DEBUGF  1, "ERROR: out of RAM\n"
839
        or      [ebp + http_msg.flags], FLAG_NO_RAM
4206 hidnplayr 840
        jmp     .disconnect
841
 
842
  .socket_error:
843
        DEBUGF  1, "ERROR: socket error %u\n", ebx
844
        or      [ebp + http_msg.flags], FLAG_SOCKET_ERROR
845
  .disconnect:
4205 hidnplayr 846
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
847
        mcall   close, [ebp + http_msg.socket]
4206 hidnplayr 848
  .connection_closed:
4158 hidnplayr 849
        popa
850
        xor     eax, eax
851
        ret
852
 
853
endp
854
 
855
 
856
 
4205 hidnplayr 857
 
4158 hidnplayr 858
;;================================================================================================;;
4205 hidnplayr 859
proc HTTP_free identifier ;///////////////////////////////////////////////////////////////////////;;
860
;;------------------------------------------------------------------------------------------------;;
861
;? Free the http_msg structure                                                                    ;;
862
;;------------------------------------------------------------------------------------------------;;
863
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
864
;;------------------------------------------------------------------------------------------------;;
865
;< none                                                                                           ;;
866
;;================================================================================================;;
867
 
868
        pusha
869
        mov     ebp, [identifier]
870
 
871
        test    [ebp + http_msg.flags], FLAG_CONNECTED
872
        jz      .not_connected
873
 
874
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
875
        mcall   close, [ebp + http_msg.socket]
876
 
877
  .not_connected:
878
        invoke  mem.free, ebp
879
 
880
        popa
881
        ret
882
 
883
endp
884
 
885
 
886
 
887
;;================================================================================================;;
888
proc HTTP_stop identifier ;///////////////////////////////////////////////////////////////////////;;
889
;;------------------------------------------------------------------------------------------------;;
890
;? Stops the open connection                                                                      ;;
891
;;------------------------------------------------------------------------------------------------;;
892
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
893
;;------------------------------------------------------------------------------------------------;;
894
;< none                                                                                           ;;
895
;;================================================================================================;;
896
 
897
        pusha
898
        mov     ebp, [identifier]
899
 
900
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
901
        mcall   close, [ebp + http_msg.socket]
902
 
903
        popa
904
        ret
905
 
906
endp
907
 
908
 
909
 
910
;;================================================================================================;;
4222 hidnplayr 911
proc HTTP_find_header_field identifier, headername ;//////////////////////////////////////////////;;
4158 hidnplayr 912
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 913
;? Find a header field in the received HTTP header                                                ;;
4158 hidnplayr 914
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 915
;> identifier   = ptr to http_msg struct                                                          ;;
916
;> headername   = ptr to ASCIIZ string containg field you want to find (must be in lowercase)     ;;
4158 hidnplayr 917
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 918
;< eax = 0 (error) / ptr to content of the HTTP header field                                      ;;
4158 hidnplayr 919
;;================================================================================================;;
920
        push    ebx ecx edx esi edi
921
 
922
        DEBUGF  1, "Find header field: %s\n", [headername]
923
 
924
        mov     ebx, [identifier]
4202 hidnplayr 925
        test    [ebx + http_msg.flags], FLAG_GOT_HEADER
926
        jz      .fail
927
 
4158 hidnplayr 928
        lea     edx, [ebx + http_msg.data]
929
        mov     ecx, edx
930
        add     ecx, [ebx + http_msg.header_length]
931
 
932
  .restart:
933
        mov     esi, [headername]
934
        mov     edi, edx
935
  .loop:
936
        cmp     edi, ecx
937
        jae     .fail
938
        lodsb
939
        scasb
940
        je      .loop
941
        test    al, al
942
        jz      .done?
943
  .next:
944
        inc     edx
945
        jmp     .restart
946
 
947
  .not_done:
948
        inc     edi
949
  .done?:
950
        cmp     byte[edi-1], ':'
951
        je      .almost_done
952
        cmp     byte[edi-1], ' '
953
        je      .not_done
954
        cmp     byte[edi-1], 9  ; tab
955
        je      .not_done
956
 
957
        jmp     .next
958
 
959
  .almost_done:                 ; FIXME: buffer overflow?
960
        dec     edi
961
        DEBUGF  1, "Found header field\n"
962
  .spaceloop:
963
        inc     edi
964
        cmp     byte[edi], ' '
965
        je      .spaceloop
966
        cmp     byte[edi], 9    ; tab
967
        je      .spaceloop
968
 
969
        mov     eax, edi
970
        pop     edi esi edx ecx ebx
971
        ret
972
 
973
  .fail:
974
        pop     edi esi edx ecx ebx
975
        xor     eax, eax
976
        ret
977
 
978
endp
979
 
980
 
981
 
4209 hidnplayr 982
;;================================================================================================;;
983
proc URI_escape URI ;/////////////////////////////////////////////////////////////////////////////;;
984
;;------------------------------------------------------------------------------------------------;;
985
;?                                                                                                ;;
986
;;------------------------------------------------------------------------------------------------;;
987
;> URI = ptr to ASCIIZ URI                                                                        ;;
988
;;------------------------------------------------------------------------------------------------;;
989
;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
990
;;================================================================================================;;
4202 hidnplayr 991
 
4209 hidnplayr 992
        pusha
4205 hidnplayr 993
 
4209 hidnplayr 994
        invoke  mem.alloc, URLMAXLEN
995
        test    eax, eax
996
        jz      .error
997
        mov     [esp + 7 * 4], eax              ; return ptr in eax
998
        mov     esi, [URI]
999
        mov     edi, eax
1000
        xor     ebx, ebx
1001
        xor     ecx, ecx
1002
  .loop:
1003
        lodsb
1004
        test    al, al
1005
        jz      .done
1006
 
1007
        mov     cl, al
1008
        and     cl, 0x1f
1009
        mov     bl, al
1010
        shr     bl, 5
1011
        bt      dword[bits_must_escape + ebx], ecx
1012
        jc      .escape
1013
 
1014
        stosb
1015
        jmp     .loop
1016
 
1017
  .escape:
1018
        mov     al, '%'
1019
        stosb
1020
        mov     bl, byte[esi-1]
1021
        shr     bl, 4
1022
        mov     al, byte[str_hex + ebx]
1023
        stosb
1024
        mov     bl, byte[esi-1]
1025
        and     bl, 0x0f
1026
        mov     al, byte[str_hex + ebx]
1027
        stosb
1028
        jmp     .loop
1029
 
1030
 
1031
  .done:
1032
        stosb
1033
 
1034
        popa
1035
        ret
1036
 
1037
  .error:
1038
        popa
1039
        xor     eax, eax
1040
        ret
1041
 
1042
endp
1043
 
1044
 
1045
 
4167 hidnplayr 1046
;;================================================================================================;;
4209 hidnplayr 1047
proc URI_unescape URI ;///////////////////////////////////////////////////////////////////////////;;
1048
;;------------------------------------------------------------------------------------------------;;
1049
;?                                                                                                ;;
1050
;;------------------------------------------------------------------------------------------------;;
1051
;> URI = ptr to ASCIIZ URI                                                                        ;;
1052
;;------------------------------------------------------------------------------------------------;;
1053
;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
1054
;;================================================================================================;;
1055
 
1056
        pusha
1057
 
1058
        invoke  mem.alloc, URLMAXLEN
1059
        test    eax, eax
1060
        jz      .error
1061
        mov     [esp + 7 * 4], eax              ; return ptr in eax
1062
        mov     esi, [URI]
1063
        mov     edi, eax
1064
  .loop:
1065
        lodsb
1066
        test    al, al
1067
        jz      .done
1068
 
1069
        cmp     al, '%'
1070
        je      .unescape
1071
 
1072
        stosb
1073
        jmp     .loop
1074
 
1075
  .unescape:
1076
        xor     ebx, ebx
1077
        xor     ecx, ecx
1078
  .unescape_nibble:
1079
        lodsb
1080
        sub     al, '0'
1081
        jb      .fail
1082
        cmp     al, 9
1083
        jbe     .nibble_ok
1084
        sub     al, 'A' - '0' - 10
1085
        jb      .fail
1086
        cmp     al, 15
1087
        jbe     .nibble_ok
1088
        sub     al, 'a' - 'A'
1089
        cmp     al, 15
1090
        ja      .fail
1091
  .nibble_ok:
1092
        shl     bl, 8
1093
        or      bl, al
1094
        dec     ecx
1095
        jc      .unescape_nibble
1096
        mov     al, bl
1097
        stosb
1098
        jmp     .loop
1099
 
1100
  .fail:
1101
        DEBUGF  1, "ERROR: invalid URI!\n"
1102
        jmp     .loop
1103
 
1104
  .done:
1105
        stosb
1106
 
1107
        popa
1108
        ret
1109
 
1110
  .error:
1111
        popa
1112
        xor     eax, eax
1113
        ret
1114
 
1115
endp
1116
 
1117
 
1118
 
1119
 
1120
 
1121
;;================================================================================================;;
4202 hidnplayr 1122
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1123
;;================================================================================================;;
1124
;! Internal procedures section                                                                    ;;
4220 hidnplayr 1125
;;                                                                                                ;;
1126
;; NOTICE: These procedures do not follow stdcall conventions and thus may destroy any register.  ;;
4202 hidnplayr 1127
;;================================================================================================;;
1128
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1129
;;================================================================================================;;
1130
 
1131
 
1132
 
1133
 
1134
;;================================================================================================;;
4167 hidnplayr 1135
proc open_connection hostname, port ;/////////////////////////////////////////////////////////////;;
1136
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1137
;? Connects to a HTTP server                                                                      ;;
4167 hidnplayr 1138
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1139
;> hostname     = ptr to ASCIIZ hostname                                                          ;;
1140
;> port         = port (x86 byte order)                                                           ;;
4167 hidnplayr 1141
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1142
;< eax = 0 (error) / socketnum                                                                    ;;
4167 hidnplayr 1143
;;================================================================================================;;
4158 hidnplayr 1144
 
4167 hidnplayr 1145
locals
1146
        sockaddr        dd ?
1147
        socketnum       dd ?
1148
endl
1149
 
1150
; Resolve the hostname
1151
        DEBUGF  1, "Resolving hostname\n"
1152
        push    esp     ; reserve stack place
1153
        push    esp     ; fourth parameter
1154
        push    0       ; third parameter
1155
        push    0       ; second parameter
1156
        push    [hostname]
1157
        call    [getaddrinfo]
1158
        pop     esi
1159
        test    eax, eax
1160
        jnz     .error1
1161
 
1162
; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct
1163
        mov     esi, [esi + addrinfo.ai_addr]
1164
        mov     [sockaddr], esi
1165
        mov     eax, [esi + sockaddr_in.sin_addr]
1166
        test    eax, eax
1167
        jz      .error2
1168
 
1169
        DEBUGF  1, "Server ip=%u.%u.%u.%u\n", \
1170
        [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \
1171
        [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1
1172
 
1173
        mov     [esi + sockaddr_in.sin_family], AF_INET4
1174
        mov     eax, [port]
1175
        xchg    al, ah
1176
        mov     [esi + sockaddr_in.sin_port], ax
1177
 
1178
; Connect to the server.
1179
        mcall   socket, AF_INET4, SOCK_STREAM, 0
1180
        test    eax, eax
1181
        jz      .error2
1182
        mov     [socketnum], eax
1183
        DEBUGF  1, "Socket: 0x%x\n", eax
1184
 
1185
        mcall   connect, [socketnum], [sockaddr], 18
1186
        test    eax, eax
1187
        jnz     .error2
1188
        DEBUGF  1, "Socket is now connected.\n"
1189
 
1190
; free allocated memory
1191
        push    [sockaddr]
1192
        call    [freeaddrinfo]
1193
 
1194
        mov     eax, [socketnum]
1195
        ret
1196
 
1197
  .error2:
1198
 
1199
; free allocated memory
1200
        push    [sockaddr]
1201
        call    [freeaddrinfo]
1202
 
1203
  .error1:
1204
        xor     eax, eax
1205
        ret
1206
 
1207
endp
1208
 
1209
 
4158 hidnplayr 1210
;;================================================================================================;;
1211
proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;;
1212
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1213
;? Split a given URL into hostname and pageaddr                                                   ;;
4158 hidnplayr 1214
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1215
;> URL = ptr to ASCIIZ URL                                                                        ;;
4158 hidnplayr 1216
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1217
;< eax = 0 (error) / ptr to ASCIIZ hostname                                                       ;;
1218
;< ebx = ptr to ASCIIZ pageaddr                                                                   ;;
4158 hidnplayr 1219
;;================================================================================================;;
1220
 
1221
locals
1222
        urlsize         dd ?
1223
        hostname        dd ?
1224
        pageaddr        dd ?
1225
endl
1226
 
4161 hidnplayr 1227
        DEBUGF  1, "parsing URL: %s\n", [URL]
4158 hidnplayr 1228
 
1229
; remove any leading protocol text
1230
        mov     esi, [URL]
1231
        mov     ecx, URLMAXLEN
1232
        mov     ax, '//'
1233
  .loop1:
1234
        cmp     byte[esi], 0            ; end of URL?
1235
        je      .url_ok                 ; yep, so not found
1236
        cmp     [esi], ax
1237
        je      .skip_proto
1238
        inc     esi
1239
        dec     ecx
1240
        jnz     .loop1
1241
 
4161 hidnplayr 1242
        DEBUGF  1, "Invalid URL\n"
4158 hidnplayr 1243
        xor     eax, eax
1244
        ret
1245
 
1246
  .skip_proto:
1247
        inc     esi                     ; skip the two '/'
1248
        inc     esi
1249
        mov     [URL], esi              ; update pointer so it skips protocol
1250
        jmp     .loop1                  ; we still need to find the length of the URL
1251
 
1252
  .url_ok:
1253
        sub     esi, [URL]              ; calculate total length of URL
1254
        mov     [urlsize], esi
1255
 
1256
 
1257
; now look for page delimiter - it's a '/' character
1258
        mov     ecx, esi                ; URL length
1259
        mov     edi, [URL]
1260
        mov     al, '/'
1261
        repne   scasb
4161 hidnplayr 1262
        jne     @f
4158 hidnplayr 1263
        dec     edi                     ; return one char, '/' must be part of the pageaddr
1264
        inc     ecx                     ;
4161 hidnplayr 1265
  @@:
4158 hidnplayr 1266
        push    ecx edi                 ; remember the pointer and length of pageaddr
1267
 
4222 hidnplayr 1268
 
1269
; Create new buffer and put hostname in it
4158 hidnplayr 1270
        mov     ecx, edi
1271
        sub     ecx, [URL]
1272
        inc     ecx                     ; we will add a 0 byte at the end
1273
        invoke  mem.alloc, ecx
1274
        or      eax, eax
1275
        jz      .no_mem
1276
 
1277
        mov     [hostname], eax         ; copy hostname to buffer
1278
        mov     edi, eax
1279
        mov     esi, [URL]
1280
        dec     ecx
1281
        rep     movsb
1282
        xor     al, al
1283
        stosb
1284
 
4161 hidnplayr 1285
        mov     [pageaddr], str_slash   ; assume there is no pageaddr
4158 hidnplayr 1286
        pop     esi ecx
1287
        test    ecx, ecx
1288
        jz      .no_page
1289
        inc     ecx                     ; we will add a 0 byte at the end
1290
        invoke  mem.alloc, ecx
1291
        or      eax, eax
1292
        jz      .no_mem
1293
 
1294
        mov     [pageaddr], eax         ; copy pageaddr to buffer
1295
        mov     edi, eax
1296
        dec     ecx
1297
        rep     movsb
1298
        xor     al, al
1299
        stosb
1300
  .no_page:
1301
 
1302
        mov     eax, [hostname]
1303
        mov     ebx, [pageaddr]
4221 hidnplayr 1304
        mov     ecx, 80                 ;;;; FIXME
4158 hidnplayr 1305
 
1306
        DEBUGF  1, "hostname: %s\n", eax
1307
        DEBUGF  1, "pageaddr: %s\n", ebx
4221 hidnplayr 1308
        DEBUGF  1, "port: %u\n", ecx
4158 hidnplayr 1309
 
1310
        ret
1311
 
1312
  .no_mem:
1313
        xor     eax, eax
1314
        ret
1315
 
1316
endp
1317
 
1318
 
4202 hidnplayr 1319
;;================================================================================================;;
1320
proc ascii_dec ;//////////////////////////////////////////////////////////////////////////////////;;
1321
;;------------------------------------------------------------------------------------------------;;
1322
;? Convert eax to ASCII decimal number                                                            ;;
1323
;;------------------------------------------------------------------------------------------------;;
1324
;> eax = number                                                                                   ;;
1325
;> edi = ptr where to write ASCII decimal number                                                  ;;
1326
;;------------------------------------------------------------------------------------------------;;
1327
;< /                                                                                              ;;
1328
;;================================================================================================;;
4158 hidnplayr 1329
 
4168 hidnplayr 1330
        push    -'0'
4167 hidnplayr 1331
        mov     ecx, 10
1332
  .loop:
1333
        xor     edx, edx
1334
        div     ecx
1335
        add     dl, '0'
4168 hidnplayr 1336
        push    edx
4167 hidnplayr 1337
        test    eax, eax
1338
        jnz     .loop
4158 hidnplayr 1339
 
4168 hidnplayr 1340
  .loop2:
1341
        pop     eax
1342
        add     al, '0'
1343
        jz      .done
1344
        stosb
1345
        jmp     .loop2
1346
  .done:
1347
 
4167 hidnplayr 1348
        ret
4158 hidnplayr 1349
 
4202 hidnplayr 1350
endp
4167 hidnplayr 1351
 
4202 hidnplayr 1352
 
4158 hidnplayr 1353
;;================================================================================================;;
1354
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1355
;;================================================================================================;;
1356
;! Imported functions section                                                                     ;;
1357
;;================================================================================================;;
1358
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1359
;;================================================================================================;;
1360
 
1361
 
1362
align 16
1363
@IMPORT:
1364
 
1365
library \
1366
        libini, 'libini.obj', \
1367
        network, 'network.obj'
1368
 
1369
import  libini, \
1370
        ini.get_str, 'ini_get_str', \
1371
        ini.get_int, 'ini_get_int'
1372
 
1373
import  network,\
1374
        getaddrinfo, 'getaddrinfo',\
1375
        freeaddrinfo,  'freeaddrinfo',\
1376
        inet_ntoa, 'inet_ntoa'
1377
 
1378
;;===========================================================================;;
1379
;;///////////////////////////////////////////////////////////////////////////;;
1380
;;===========================================================================;;
1381
;! Exported functions section                                                ;;
1382
;;===========================================================================;;
1383
;;///////////////////////////////////////////////////////////////////////////;;
1384
;;===========================================================================;;
1385
 
1386
 
1387
align 4
1388
@EXPORT:
1389
export  \
1390
        lib_init                , 'lib_init'            , \
1391
        0x00010001              , 'version'             , \
1392
        HTTP_get                , 'get'                 , \
4167 hidnplayr 1393
        HTTP_head               , 'head'                , \
1394
        HTTP_post               , 'post'                , \
4222 hidnplayr 1395
        HTTP_find_header_field  , 'find_header_field'   , \
4205 hidnplayr 1396
        HTTP_process            , 'process'             , \
1397
        HTTP_free               , 'free'                , \
4209 hidnplayr 1398
        HTTP_stop               , 'stop'                , \
1399
        URI_escape              , 'escape'              , \
1400
        URI_unescape            , 'unescape'
4158 hidnplayr 1401
 
1402
;        HTTP_put                , 'put'                 , \
1403
;        HTTP_delete             , 'delete'              , \
1404
;        HTTP_trace              , 'trace'               , \
1405
;        HTTP_connect            , 'connect'             , \
1406
 
1407
 
1408
 
1409
section '.data' data readable writable align 16
1410
 
1411
inifile         db '/sys/settings/network.ini', 0
1412
 
1413
sec_proxy:
1414
key_proxy       db 'proxy', 0
1415
key_proxyport   db 'port', 0
1416
key_user        db 'user', 0
1417
key_password    db 'password', 0
1418
 
1419
str_http11      db ' HTTP/1.1', 13, 10, 'Host: '
1420
  .length       = $ - str_http11
4167 hidnplayr 1421
str_post_cl     db 13, 10, 'Content-Length: '
1422
  .length       = $ - str_post_cl
1423
str_post_ct     db 13, 10, 'Content-Type: '
1424
  .length       = $ - str_post_ct
4158 hidnplayr 1425
str_close       db 13, 10, 'User-Agent: KolibriOS libHTTP/1.0', 13, 10, 'Connection: Close', 13, 10, 13, 10
1426
  .length       = $ - str_close
1427
str_proxy_auth  db 13, 10, 'Proxy-Authorization: Basic '
1428
  .length       = $ - str_proxy_auth
1429
 
1430
base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
1431
                db '0123456789+/'
1432
 
1433
str_cl          db 'content-length', 0
4161 hidnplayr 1434
str_slash       db '/', 0
4158 hidnplayr 1435
str_te          db 'transfer-encoding', 0
4167 hidnplayr 1436
str_get         db 'GET ', 0
1437
str_head        db 'HEAD ', 0
1438
str_post        db 'POST ', 0
4158 hidnplayr 1439
 
4209 hidnplayr 1440
bits_must_escape:
1441
dd      0xffffffff                                                      ; 00-1F
1442
dd      1 shl 0 + 1 shl 2 + 1 shl 3 + 1 shl 5 + 1 shl 28 + 1 shl 30     ; "#%<>
1443
dd      1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 30                       ;[\]^
1444
dd      1 shl 0 + 1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 31             ;`{|} DEL
1445
 
1446
dd      0xffffffff
1447
dd      0xffffffff
1448
dd      0xffffffff
1449
dd      0xffffffff
1450
 
1451
str_hex:
1452
db '0123456789ABCDEF'
1453
 
4158 hidnplayr 1454
include_debug_strings
1455
 
1456
; uninitialized data
1457
mem.alloc       dd ?
1458
mem.free        dd ?
1459
mem.realloc     dd ?
1460
dll.load        dd ?
1461
 
1462
proxyAddr       rb 256
1463
proxyUser       rb 256
1464
proxyPassword   rb 256
1465
proxyPort       dd ?