Subversion Repositories Kolibri OS

Rev

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