Subversion Repositories Kolibri OS

Rev

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

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