Subversion Repositories Kolibri OS

Rev

Rev 4233 | Rev 4541 | 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                            ;;
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
22
        BUFFERSIZE      = 4096
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]
62
        lea     esi, [eax + http_msg.data]
4205 hidnplayr 63
        mov     [eax + http_msg.flags], FLAG_CONNECTED
4167 hidnplayr 64
        mov     [eax + http_msg.write_ptr], esi
65
        mov     [eax + http_msg.buffer_length], BUFFERSIZE -  http_msg.data
66
        mov     [eax + http_msg.chunk_ptr], 0
67
 
68
        mov     [eax + http_msg.status], 0
69
        mov     [eax + http_msg.header_length], 0
70
        mov     [eax + http_msg.content_length], 0
4168 hidnplayr 71
        mov     [eax + http_msg.content_received], 0
4206 hidnplayr 72
 
73
        push    eax ebp
74
        mov     ebp, eax
75
        mcall   29, 9
76
        mov     [ebp + http_msg.timestamp], eax
77
        pop     ebp eax
4167 hidnplayr 78
}
79
 
4158 hidnplayr 80
section '.flat' code readable align 16
81
 
82
;;===========================================================================;;
83
lib_init: ;//////////////////////////////////////////////////////////////////;;
84
;;---------------------------------------------------------------------------;;
85
;? Library entry point (called after library load)                           ;;
86
;;---------------------------------------------------------------------------;;
87
;> eax = pointer to memory allocation routine                                ;;
88
;> ebx = pointer to memory freeing routine                                   ;;
89
;> ecx = pointer to memory reallocation routine                              ;;
90
;> edx = pointer to library loading routine                                  ;;
91
;;---------------------------------------------------------------------------;;
4209 hidnplayr 92
;< eax = 1 (fail) / 0 (ok)                                                   ;;
4158 hidnplayr 93
;;===========================================================================;;
94
        mov     [mem.alloc], eax
95
        mov     [mem.free], ebx
96
        mov     [mem.realloc], ecx
97
        mov     [dll.load], edx
98
 
99
        invoke  dll.load, @IMPORT
4209 hidnplayr 100
        test    eax, eax
101
        jnz     .error
4158 hidnplayr 102
 
103
; load proxy settings
4216 hidnplayr 104
        pusha
4158 hidnplayr 105
        invoke  ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
106
        invoke  ini.get_int, inifile, sec_proxy, key_proxyport, 80
107
        mov     [proxyPort], eax
108
        invoke  ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
109
        invoke  ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
4216 hidnplayr 110
        popa
4158 hidnplayr 111
 
4212 hidnplayr 112
        DEBUGF  1, "HTTP library: init OK\n"
4211 hidnplayr 113
 
4158 hidnplayr 114
        xor     eax, eax
115
        ret
116
 
4209 hidnplayr 117
  .error:
4212 hidnplayr 118
        DEBUGF  1, "ERROR loading libraries\n"
4211 hidnplayr 119
 
4158 hidnplayr 120
        xor     eax, eax
4209 hidnplayr 121
        inc     eax
122
 
4158 hidnplayr 123
        ret
124
 
125
 
126
 
127
 
128
;;================================================================================================;;
4221 hidnplayr 129
proc HTTP_get URL, add_header ;///////////////////////////////////////////////////////////////////;;
4158 hidnplayr 130
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 131
;? Initiates a HTTP connection, using 'GET' method.                                               ;;
4158 hidnplayr 132
;;------------------------------------------------------------------------------------------------;;
4221 hidnplayr 133
;> URL          = pointer to ASCIIZ URL                                                           ;;
134
;> add_header   = pointer to additional header parameters (ASCIIZ), or null for none.             ;;
4158 hidnplayr 135
;;------------------------------------------------------------------------------------------------;;
136
;< eax = 0 (error) / buffer ptr                                                                   ;;
137
;;================================================================================================;;
138
locals
139
        hostname        dd ?
140
        pageaddr        dd ?
141
        sockaddr        dd ?
142
        socketnum       dd ?
143
        buffer          dd ?
4167 hidnplayr 144
        port            dd ?
4158 hidnplayr 145
endl
146
 
4216 hidnplayr 147
        pusha
148
 
4158 hidnplayr 149
; split the URL into hostname and pageaddr
150
        stdcall parse_url, [URL]
151
        test    eax, eax
152
        jz      .error
153
        mov     [hostname], eax
154
        mov     [pageaddr], ebx
4221 hidnplayr 155
        mov     [port], ecx
4158 hidnplayr 156
 
4167 hidnplayr 157
; Connect to the other side.
158
        stdcall open_connection, [hostname], [port]
4158 hidnplayr 159
        test    eax, eax
4167 hidnplayr 160
        jz      .error
161
        mov     [socketnum], eax
4158 hidnplayr 162
 
4167 hidnplayr 163
; Create the HTTP request.
164
        invoke  mem.alloc, BUFFERSIZE
4158 hidnplayr 165
        test    eax, eax
166
        jz      .error
4167 hidnplayr 167
        mov     [buffer], eax
168
        mov     edi, eax
169
        DEBUGF  1, "Buffer has been allocated.\n"
4158 hidnplayr 170
 
4167 hidnplayr 171
        mov     esi, str_get
172
        copy_till_zero
4158 hidnplayr 173
 
4233 hidnplayr 174
; If we are using a proxy, send complete URL, otherwise send only page address.
175
        cmp     [proxyAddr], 0
176
        je      .no_proxy
177
        mov     esi, str_http           ; prepend 'http://'
178
        copy_till_zero
179
        mov     esi, [hostname]
180
        copy_till_zero
181
  .no_proxy:
4167 hidnplayr 182
        mov     esi, [pageaddr]
183
        copy_till_zero
4158 hidnplayr 184
 
4167 hidnplayr 185
        mov     esi, str_http11
186
        mov     ecx, str_http11.length
187
        rep     movsb
188
 
189
        mov     esi, [hostname]
190
        copy_till_zero
191
 
4241 hidnplayr 192
        cmp     byte[proxyUser], 0
193
        je      @f
194
        call    append_proxy_auth_header
195
  @@:
196
 
197
        mov     ax, 0x0a0d
198
        stosw
199
 
4221 hidnplayr 200
        mov     esi, [add_header]
201
        test    esi, esi
202
        jz      @f
203
        copy_till_zero
204
  @@:
205
 
4167 hidnplayr 206
        mov     esi, str_close
207
        mov     ecx, str_close.length
208
        rep     movsb
209
 
210
        mov     byte[edi], 0
211
        DEBUGF  1, "Request:\n%s", [buffer]
212
 
4222 hidnplayr 213
; Free unused memory
214
        push    edi
215
        invoke  mem.free, [pageaddr]
216
        invoke  mem.free, [hostname]
217
        pop     esi
218
 
4167 hidnplayr 219
; Send the request
220
        sub     esi, [buffer]   ; length
221
        xor     edi, edi        ; flags
222
        mcall   send, [socketnum], [buffer]
4158 hidnplayr 223
        test    eax, eax
224
        jz      .error
4167 hidnplayr 225
        DEBUGF  1, "Request has been sent to server.\n"
4158 hidnplayr 226
 
4167 hidnplayr 227
        HTTP_init_buffer [buffer], [socketnum]
228
 
4216 hidnplayr 229
        popa
230
        mov     eax, [buffer]   ; return buffer ptr
231
        ret
4167 hidnplayr 232
 
233
  .error:
234
        DEBUGF  1, "Error!\n"
4216 hidnplayr 235
        popa
4167 hidnplayr 236
        xor     eax, eax        ; return 0 = error
237
        ret
238
 
239
endp
240
 
241
 
242
 
243
;;================================================================================================;;
4221 hidnplayr 244
proc HTTP_head URL, add_header ;//////////////////////////////////////////////////////////////////;;
4167 hidnplayr 245
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 246
;? Initiates a HTTP connection, using 'HEAD' method.                                              ;;
4167 hidnplayr 247
;;------------------------------------------------------------------------------------------------;;
4221 hidnplayr 248
;> URL          = pointer to ASCIIZ URL                                                           ;;
249
;> add_header   = pointer to additional header parameters (ASCIIZ), or null for none.             ;;
4167 hidnplayr 250
;;------------------------------------------------------------------------------------------------;;
251
;< eax = 0 (error) / buffer ptr                                                                   ;;
252
;;================================================================================================;;
253
locals
254
        hostname        dd ?
255
        pageaddr        dd ?
256
        sockaddr        dd ?
257
        socketnum       dd ?
258
        buffer          dd ?
259
        port            dd ?
260
endl
261
 
4216 hidnplayr 262
        pusha
4167 hidnplayr 263
; split the URL into hostname and pageaddr
264
        stdcall parse_url, [URL]
4158 hidnplayr 265
        test    eax, eax
4167 hidnplayr 266
        jz      .error
267
        mov     [hostname], eax
268
        mov     [pageaddr], ebx
4221 hidnplayr 269
        mov     [port], ecx
4158 hidnplayr 270
 
4167 hidnplayr 271
; Connect to the other side.
272
        stdcall open_connection, [hostname], [port]
273
        test    eax, eax
274
        jz      .error
275
        mov     [socketnum], eax
276
 
4158 hidnplayr 277
; Create the HTTP request.
278
        invoke  mem.alloc, BUFFERSIZE
279
        test    eax, eax
280
        jz      .error
281
        mov     [buffer], eax
4167 hidnplayr 282
        mov     edi, eax
4158 hidnplayr 283
        DEBUGF  1, "Buffer has been allocated.\n"
284
 
4167 hidnplayr 285
        mov     esi, str_head
4158 hidnplayr 286
        copy_till_zero
287
 
4233 hidnplayr 288
; If we are using a proxy, send complete URL, otherwise send only page address.
289
        cmp     [proxyAddr], 0
290
        je      .no_proxy
291
        mov     esi, str_http           ; prepend 'http://'
292
        copy_till_zero
293
        mov     esi, [hostname]
294
        copy_till_zero
295
  .no_proxy:
4167 hidnplayr 296
        mov     esi, [pageaddr]
297
        copy_till_zero
298
 
4158 hidnplayr 299
        mov     esi, str_http11
300
        mov     ecx, str_http11.length
301
        rep     movsb
302
 
303
        mov     esi, [hostname]
304
        copy_till_zero
305
 
4241 hidnplayr 306
        cmp     byte[proxyUser], 0
307
        je      @f
308
        call    append_proxy_auth_header
309
  @@:
310
 
311
        mov     ax, 0x0a0d
312
        stosw
313
 
4221 hidnplayr 314
        mov     esi, [add_header]
315
        test    esi, esi
316
        jz      @f
317
        copy_till_zero
318
  @@:
319
 
4158 hidnplayr 320
        mov     esi, str_close
321
        mov     ecx, str_close.length
322
        rep     movsb
323
 
324
        mov     byte[edi], 0
325
        DEBUGF  1, "Request:\n%s", [buffer]
326
 
4222 hidnplayr 327
 
328
; Free unused memory
329
        push    edi
330
        invoke  mem.free, [pageaddr]
331
        invoke  mem.free, [hostname]
332
        pop     esi
333
 
4167 hidnplayr 334
; Send the request
4158 hidnplayr 335
        sub     esi, [buffer]   ; length
336
        xor     edi, edi        ; flags
337
        mcall   send, [socketnum], [buffer]
338
        test    eax, eax
339
        jz      .error
340
        DEBUGF  1, "Request has been sent to server.\n"
341
 
4167 hidnplayr 342
        HTTP_init_buffer [buffer], [socketnum]
4158 hidnplayr 343
 
4216 hidnplayr 344
        popa
345
        mov     eax, [buffer]
4167 hidnplayr 346
        ret                     ; return buffer ptr
4158 hidnplayr 347
 
4167 hidnplayr 348
  .error:
349
        DEBUGF  1, "Error!\n"
4216 hidnplayr 350
        popa
4167 hidnplayr 351
        xor     eax, eax        ; return 0 = error
352
        ret
353
 
354
endp
355
 
356
 
357
;;================================================================================================;;
4221 hidnplayr 358
proc HTTP_post URL, add_header, content_type, content_length ;////////////////////////////////////;;
4167 hidnplayr 359
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 360
;? Initiates a HTTP connection, using 'GET' method.                                               ;;
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
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]
538
        sub     eax, http_msg.data
539
        sub     eax, ebp
540
        sub     eax, [ebp + http_msg.header_length]
541
        ; edi is ptr to begin of header
542
        lea     edi, [ebp + http_msg.data]
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:
560
        add     edi, 4 - http_msg.data
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
 
604
        lea     esi, [ebp + http_msg.data]
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
637
        lea     esi, [ebp + http_msg.data]
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
 
669
; Resize buffer according to content-length.
4168 hidnplayr 670
        add     edx, [ebp + http_msg.header_length]
671
        add     edx, http_msg.data
4158 hidnplayr 672
 
4168 hidnplayr 673
        mov     ecx, edx
4158 hidnplayr 674
        sub     ecx, [ebp + http_msg.write_ptr]
675
        mov     [ebp + http_msg.buffer_length], ecx
676
 
4168 hidnplayr 677
        invoke  mem.realloc, ebp, edx
4158 hidnplayr 678
        or      eax, eax
4212 hidnplayr 679
        jz      .no_ram
4203 hidnplayr 680
 
4220 hidnplayr 681
  .not_chunked:
4212 hidnplayr 682
        mov     eax, [ebp + http_msg.write_ptr]
4168 hidnplayr 683
        sub     eax, [ebp + http_msg.header_length]
4212 hidnplayr 684
        sub     eax, http_msg.data
685
        sub     eax, ebp
4158 hidnplayr 686
        jmp     .header_parsed  ; hooray!
687
 
688
  .no_content:
689
        DEBUGF  1, "Content-length not found.\n"
690
 
691
; We didnt find 'content-length', maybe server is using chunked transfer encoding?
692
; Try to find 'transfer-encoding' header.
4222 hidnplayr 693
        stdcall HTTP_find_header_field, ebp, str_te
4158 hidnplayr 694
        test    eax, eax
4220 hidnplayr 695
        jz      .not_chunked
4158 hidnplayr 696
 
697
        mov     ebx, dword[eax]
4162 hidnplayr 698
        or      ebx, 0x20202020
4158 hidnplayr 699
        cmp     ebx, 'chun'
4220 hidnplayr 700
        jne     .not_chunked
4158 hidnplayr 701
        mov     ebx, dword[eax+4]
4162 hidnplayr 702
        or      ebx, 0x00202020
703
        and     ebx, 0x00ffffff
4158 hidnplayr 704
        cmp     ebx, 'ked'
4220 hidnplayr 705
        jne     .not_chunked
4158 hidnplayr 706
 
707
        or      [ebp + http_msg.flags], FLAG_CHUNKED
708
        DEBUGF  1, "Transfer type is: chunked\n"
709
 
710
; Set chunk pointer where first chunk should begin.
4162 hidnplayr 711
        lea     eax, [ebp + http_msg.data]
712
        add     eax, [ebp + http_msg.header_length]
4158 hidnplayr 713
        mov     [ebp + http_msg.chunk_ptr], eax
714
 
4162 hidnplayr 715
  .chunk_loop:
4158 hidnplayr 716
        mov     ecx, [ebp + http_msg.write_ptr]
717
        sub     ecx, [ebp + http_msg.chunk_ptr]
4202 hidnplayr 718
        jb      .need_more_data_chunked         ; TODO: use this ecx !!!
4158 hidnplayr 719
 
4202 hidnplayr 720
; Chunkline starts here, convert the ASCII hex number into ebx
4158 hidnplayr 721
        mov     esi, [ebp + http_msg.chunk_ptr]
722
        xor     ebx, ebx
723
  .chunk_hexloop:
724
        lodsb
725
        sub     al, '0'
726
        jb      .chunk_
727
        cmp     al, 9
728
        jbe     .chunk_hex
4162 hidnplayr 729
        sub     al, 'A' - '0' - 10
4158 hidnplayr 730
        jb      .chunk_
4162 hidnplayr 731
        cmp     al, 15
4158 hidnplayr 732
        jbe     .chunk_hex
733
        sub     al, 'a' - 'A'
4162 hidnplayr 734
        cmp     al, 15
4158 hidnplayr 735
        ja      .chunk_
736
  .chunk_hex:
737
        shl     ebx, 4
738
        add     bl, al
739
        jmp     .chunk_hexloop
740
  .chunk_:
741
        DEBUGF  1, "got chunk of %u bytes\n", ebx
4202 hidnplayr 742
;;        cmp     esi, [ebp + http_msg.chunk_ptr]
743
;;        je
4158 hidnplayr 744
; If chunk size is 0, all chunks have been received.
745
        test    ebx, ebx
4162 hidnplayr 746
        jz      .got_all_data_chunked           ; last chunk, hooray! FIXME: what if it wasnt a valid hex number???
4158 hidnplayr 747
 
748
; Chunkline ends with a CR, LF or simply LF
4202 hidnplayr 749
  .end_of_chunkline?:
4158 hidnplayr 750
        cmp     al, 10
751
        je      .end_of_chunkline
752
        lodsb
4202 hidnplayr 753
        cmp     edi, [ebp + http_msg.write_ptr]
754
        jb      .end_of_chunkline?
755
        jmp     .need_more_data
4158 hidnplayr 756
 
757
  .end_of_chunkline:
4202 hidnplayr 758
; Update chunk ptr, and remember old one
759
        mov     edi, [ebp + http_msg.chunk_ptr]
760
        add     [ebp + http_msg.chunk_ptr], ebx
4162 hidnplayr 761
; Realloc buffer, make it 'chunksize' bigger.
762
        mov     eax, [ebp + http_msg.buffer_length]
763
        add     eax, ebx
764
        invoke  mem.realloc, ebp, eax
765
        or      eax, eax
766
        jz      .no_ram
767
        add     [ebp + http_msg.buffer_length], ebx
768
 
769
; Update write ptr
770
        mov     eax, esi
771
        sub     eax, edi
772
        sub     [ebp + http_msg.write_ptr], eax
773
 
4158 hidnplayr 774
; Now move all received data to the left (remove chunk header).
4162 hidnplayr 775
; Update content_length accordingly.
4158 hidnplayr 776
        mov     ecx, [ebp + http_msg.write_ptr]
777
        sub     ecx, esi
4168 hidnplayr 778
        add     [ebp + http_msg.content_received], ecx
4158 hidnplayr 779
        rep     movsb
4162 hidnplayr 780
        jmp     .chunk_loop
4158 hidnplayr 781
 
782
; Check if we got all the data.
4162 hidnplayr 783
  .header_parsed:
4168 hidnplayr 784
        add     [ebp + http_msg.content_received], eax
4220 hidnplayr 785
        test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
786
        jz      .need_more_data_and_space
4217 hidnplayr 787
        mov     eax, [ebp + http_msg.content_received]
788
        cmp     eax, [ebp + http_msg.content_length]
4168 hidnplayr 789
        jae     .got_all_data
4220 hidnplayr 790
        jmp     .need_more_data
4212 hidnplayr 791
 
4220 hidnplayr 792
  .need_more_data_and_space:
793
        mov     eax, [ebp + http_msg.write_ptr]
794
        add     eax, BUFFERSIZE
795
        sub     eax, ebp
796
        invoke  mem.realloc, ebp, eax
797
        or      eax, eax
798
        jz      .no_ram
799
        mov     [ebp + http_msg.buffer_length], BUFFERSIZE
800
 
4162 hidnplayr 801
  .need_more_data:
802
        popa
803
        xor     eax, eax
804
        dec     eax
805
        ret
4158 hidnplayr 806
 
4162 hidnplayr 807
  .need_more_data_chunked:
4168 hidnplayr 808
        add     [ebp + http_msg.content_received], eax
4158 hidnplayr 809
        popa
810
        xor     eax, eax
811
        dec     eax
812
        ret
813
 
4162 hidnplayr 814
  .got_all_data_chunked:
815
        mov     eax, [ebp + http_msg.chunk_ptr]
816
        sub     eax, [ebp + http_msg.header_length]
817
        sub     eax, http_msg.data
818
        sub     eax, ebp
819
        mov     [ebp + http_msg.content_length], eax
4168 hidnplayr 820
        mov     [ebp + http_msg.content_received], eax
4158 hidnplayr 821
  .got_all_data:
4217 hidnplayr 822
        DEBUGF  1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_received]
4205 hidnplayr 823
        or      [ebp + http_msg.flags], FLAG_GOT_ALL_DATA
824
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
4158 hidnplayr 825
        mcall   close, [ebp + http_msg.socket]
826
        popa
827
        xor     eax, eax
828
        ret
829
 
830
  .check_socket:
831
        cmp     ebx, EWOULDBLOCK
4206 hidnplayr 832
        jne     .socket_error
4158 hidnplayr 833
 
4206 hidnplayr 834
        mcall   29, 9
835
        sub     eax, TIMEOUT
836
        cmp     eax, [ebp + http_msg.timestamp]
4207 hidnplayr 837
        jb      .need_more_data
4206 hidnplayr 838
        DEBUGF  1, "ERROR: timeout\n"
839
        or      [ebp + http_msg.flags], FLAG_TIMEOUT_ERROR
840
        jmp     .disconnect
4158 hidnplayr 841
 
4220 hidnplayr 842
  .server_closed:
843
        DEBUGF  1, "server closed connection, transfer complete?\n"
844
        test    [ebp + http_msg.flags], FLAG_GOT_HEADER
845
        jz      .server_error
846
        test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
847
        jz      .got_all_data
848
 
849
  .server_error:
850
        pop     eax
851
        DEBUGF  1, "ERROR: server closed connection unexpectedly\n"
852
        or      [ebp + http_msg.flags], FLAG_TRANSFER_FAILED
853
        jmp     .disconnect
854
 
4158 hidnplayr 855
  .invalid_header:
4203 hidnplayr 856
        pop     eax
4158 hidnplayr 857
        DEBUGF  1, "ERROR: invalid header\n"
858
        or      [ebp + http_msg.flags], FLAG_INVALID_HEADER
4206 hidnplayr 859
        jmp     .disconnect
4158 hidnplayr 860
 
861
  .no_ram:
862
        DEBUGF  1, "ERROR: out of RAM\n"
863
        or      [ebp + http_msg.flags], FLAG_NO_RAM
4206 hidnplayr 864
        jmp     .disconnect
865
 
866
  .socket_error:
867
        DEBUGF  1, "ERROR: socket error %u\n", ebx
868
        or      [ebp + http_msg.flags], FLAG_SOCKET_ERROR
869
  .disconnect:
4205 hidnplayr 870
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
871
        mcall   close, [ebp + http_msg.socket]
4206 hidnplayr 872
  .connection_closed:
4158 hidnplayr 873
        popa
874
        xor     eax, eax
875
        ret
876
 
877
endp
878
 
879
 
880
 
4205 hidnplayr 881
 
4158 hidnplayr 882
;;================================================================================================;;
4205 hidnplayr 883
proc HTTP_free identifier ;///////////////////////////////////////////////////////////////////////;;
884
;;------------------------------------------------------------------------------------------------;;
885
;? Free the http_msg structure                                                                    ;;
886
;;------------------------------------------------------------------------------------------------;;
887
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
888
;;------------------------------------------------------------------------------------------------;;
889
;< none                                                                                           ;;
890
;;================================================================================================;;
891
 
892
        pusha
893
        mov     ebp, [identifier]
894
 
895
        test    [ebp + http_msg.flags], FLAG_CONNECTED
896
        jz      .not_connected
897
 
898
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
899
        mcall   close, [ebp + http_msg.socket]
900
 
901
  .not_connected:
902
        invoke  mem.free, ebp
903
 
904
        popa
905
        ret
906
 
907
endp
908
 
909
 
910
 
911
;;================================================================================================;;
912
proc HTTP_stop identifier ;///////////////////////////////////////////////////////////////////////;;
913
;;------------------------------------------------------------------------------------------------;;
914
;? Stops the open connection                                                                      ;;
915
;;------------------------------------------------------------------------------------------------;;
916
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
917
;;------------------------------------------------------------------------------------------------;;
918
;< none                                                                                           ;;
919
;;================================================================================================;;
920
 
921
        pusha
922
        mov     ebp, [identifier]
923
 
924
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
925
        mcall   close, [ebp + http_msg.socket]
926
 
927
        popa
928
        ret
929
 
930
endp
931
 
932
 
933
 
934
;;================================================================================================;;
4222 hidnplayr 935
proc HTTP_find_header_field identifier, headername ;//////////////////////////////////////////////;;
4158 hidnplayr 936
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 937
;? Find a header field in the received HTTP header                                                ;;
4158 hidnplayr 938
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 939
;> identifier   = ptr to http_msg struct                                                          ;;
940
;> headername   = ptr to ASCIIZ string containg field you want to find (must be in lowercase)     ;;
4158 hidnplayr 941
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 942
;< eax = 0 (error) / ptr to content of the HTTP header field                                      ;;
4158 hidnplayr 943
;;================================================================================================;;
944
        push    ebx ecx edx esi edi
945
 
946
        DEBUGF  1, "Find header field: %s\n", [headername]
947
 
948
        mov     ebx, [identifier]
4202 hidnplayr 949
        test    [ebx + http_msg.flags], FLAG_GOT_HEADER
950
        jz      .fail
951
 
4158 hidnplayr 952
        lea     edx, [ebx + http_msg.data]
953
        mov     ecx, edx
954
        add     ecx, [ebx + http_msg.header_length]
955
 
956
  .restart:
957
        mov     esi, [headername]
958
        mov     edi, edx
959
  .loop:
960
        cmp     edi, ecx
961
        jae     .fail
962
        lodsb
963
        scasb
964
        je      .loop
965
        test    al, al
966
        jz      .done?
967
  .next:
968
        inc     edx
969
        jmp     .restart
970
 
971
  .not_done:
972
        inc     edi
973
  .done?:
974
        cmp     byte[edi-1], ':'
975
        je      .almost_done
976
        cmp     byte[edi-1], ' '
977
        je      .not_done
978
        cmp     byte[edi-1], 9  ; tab
979
        je      .not_done
980
 
981
        jmp     .next
982
 
983
  .almost_done:                 ; FIXME: buffer overflow?
984
        dec     edi
985
        DEBUGF  1, "Found header field\n"
986
  .spaceloop:
987
        inc     edi
988
        cmp     byte[edi], ' '
989
        je      .spaceloop
990
        cmp     byte[edi], 9    ; tab
991
        je      .spaceloop
992
 
993
        mov     eax, edi
994
        pop     edi esi edx ecx ebx
995
        ret
996
 
997
  .fail:
998
        pop     edi esi edx ecx ebx
999
        xor     eax, eax
1000
        ret
1001
 
1002
endp
1003
 
1004
 
1005
 
4209 hidnplayr 1006
;;================================================================================================;;
1007
proc URI_escape URI ;/////////////////////////////////////////////////////////////////////////////;;
1008
;;------------------------------------------------------------------------------------------------;;
1009
;?                                                                                                ;;
1010
;;------------------------------------------------------------------------------------------------;;
1011
;> URI = ptr to ASCIIZ URI                                                                        ;;
1012
;;------------------------------------------------------------------------------------------------;;
1013
;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
1014
;;================================================================================================;;
4202 hidnplayr 1015
 
4209 hidnplayr 1016
        pusha
4205 hidnplayr 1017
 
4209 hidnplayr 1018
        invoke  mem.alloc, URLMAXLEN
1019
        test    eax, eax
1020
        jz      .error
1021
        mov     [esp + 7 * 4], eax              ; return ptr in eax
1022
        mov     esi, [URI]
1023
        mov     edi, eax
1024
        xor     ebx, ebx
1025
        xor     ecx, ecx
1026
  .loop:
1027
        lodsb
1028
        test    al, al
1029
        jz      .done
1030
 
1031
        mov     cl, al
1032
        and     cl, 0x1f
1033
        mov     bl, al
1034
        shr     bl, 5
1035
        bt      dword[bits_must_escape + ebx], ecx
1036
        jc      .escape
1037
 
1038
        stosb
1039
        jmp     .loop
1040
 
1041
  .escape:
1042
        mov     al, '%'
1043
        stosb
1044
        mov     bl, byte[esi-1]
1045
        shr     bl, 4
1046
        mov     al, byte[str_hex + ebx]
1047
        stosb
1048
        mov     bl, byte[esi-1]
1049
        and     bl, 0x0f
1050
        mov     al, byte[str_hex + ebx]
1051
        stosb
1052
        jmp     .loop
1053
 
1054
 
1055
  .done:
1056
        stosb
1057
 
1058
        popa
1059
        ret
1060
 
1061
  .error:
1062
        popa
1063
        xor     eax, eax
1064
        ret
1065
 
1066
endp
1067
 
1068
 
1069
 
4167 hidnplayr 1070
;;================================================================================================;;
4209 hidnplayr 1071
proc URI_unescape URI ;///////////////////////////////////////////////////////////////////////////;;
1072
;;------------------------------------------------------------------------------------------------;;
1073
;?                                                                                                ;;
1074
;;------------------------------------------------------------------------------------------------;;
1075
;> URI = ptr to ASCIIZ URI                                                                        ;;
1076
;;------------------------------------------------------------------------------------------------;;
1077
;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
1078
;;================================================================================================;;
1079
 
1080
        pusha
1081
 
1082
        invoke  mem.alloc, URLMAXLEN
1083
        test    eax, eax
1084
        jz      .error
1085
        mov     [esp + 7 * 4], eax              ; return ptr in eax
1086
        mov     esi, [URI]
1087
        mov     edi, eax
1088
  .loop:
1089
        lodsb
1090
        test    al, al
1091
        jz      .done
1092
 
1093
        cmp     al, '%'
1094
        je      .unescape
1095
 
1096
        stosb
1097
        jmp     .loop
1098
 
1099
  .unescape:
1100
        xor     ebx, ebx
1101
        xor     ecx, ecx
1102
  .unescape_nibble:
1103
        lodsb
1104
        sub     al, '0'
1105
        jb      .fail
1106
        cmp     al, 9
1107
        jbe     .nibble_ok
1108
        sub     al, 'A' - '0' - 10
1109
        jb      .fail
1110
        cmp     al, 15
1111
        jbe     .nibble_ok
1112
        sub     al, 'a' - 'A'
1113
        cmp     al, 15
1114
        ja      .fail
1115
  .nibble_ok:
1116
        shl     bl, 8
1117
        or      bl, al
1118
        dec     ecx
1119
        jc      .unescape_nibble
1120
        mov     al, bl
1121
        stosb
1122
        jmp     .loop
1123
 
1124
  .fail:
1125
        DEBUGF  1, "ERROR: invalid URI!\n"
1126
        jmp     .loop
1127
 
1128
  .done:
1129
        stosb
1130
 
1131
        popa
1132
        ret
1133
 
1134
  .error:
1135
        popa
1136
        xor     eax, eax
1137
        ret
1138
 
1139
endp
1140
 
1141
 
1142
 
1143
 
1144
 
1145
;;================================================================================================;;
4202 hidnplayr 1146
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1147
;;================================================================================================;;
1148
;! Internal procedures section                                                                    ;;
4220 hidnplayr 1149
;;                                                                                                ;;
1150
;; NOTICE: These procedures do not follow stdcall conventions and thus may destroy any register.  ;;
4202 hidnplayr 1151
;;================================================================================================;;
1152
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1153
;;================================================================================================;;
1154
 
1155
 
1156
 
1157
 
1158
;;================================================================================================;;
4167 hidnplayr 1159
proc open_connection hostname, port ;/////////////////////////////////////////////////////////////;;
1160
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1161
;? Connects to a HTTP server                                                                      ;;
4167 hidnplayr 1162
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1163
;> hostname     = ptr to ASCIIZ hostname                                                          ;;
1164
;> port         = port (x86 byte order)                                                           ;;
4167 hidnplayr 1165
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1166
;< eax = 0 (error) / socketnum                                                                    ;;
4167 hidnplayr 1167
;;================================================================================================;;
4158 hidnplayr 1168
 
4167 hidnplayr 1169
locals
1170
        sockaddr        dd ?
1171
        socketnum       dd ?
1172
endl
1173
 
4233 hidnplayr 1174
        cmp     [proxyAddr], 0
1175
        je      .no_proxy
1176
 
1177
        mov     [hostname], proxyAddr
1178
 
1179
        push    [proxyPort]
1180
        pop     [port]
1181
  .no_proxy:
1182
 
4167 hidnplayr 1183
; Resolve the hostname
1184
        DEBUGF  1, "Resolving hostname\n"
1185
        push    esp     ; reserve stack place
1186
        push    esp     ; fourth parameter
1187
        push    0       ; third parameter
1188
        push    0       ; second parameter
1189
        push    [hostname]
1190
        call    [getaddrinfo]
1191
        pop     esi
1192
        test    eax, eax
1193
        jnz     .error1
1194
 
1195
; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct
1196
        mov     esi, [esi + addrinfo.ai_addr]
1197
        mov     [sockaddr], esi
1198
        mov     eax, [esi + sockaddr_in.sin_addr]
1199
        test    eax, eax
1200
        jz      .error2
1201
 
1202
        DEBUGF  1, "Server ip=%u.%u.%u.%u\n", \
1203
        [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \
1204
        [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1
1205
 
1206
        mov     [esi + sockaddr_in.sin_family], AF_INET4
1207
        mov     eax, [port]
1208
        xchg    al, ah
1209
        mov     [esi + sockaddr_in.sin_port], ax
1210
 
1211
; Connect to the server.
1212
        mcall   socket, AF_INET4, SOCK_STREAM, 0
1213
        test    eax, eax
1214
        jz      .error2
1215
        mov     [socketnum], eax
1216
        DEBUGF  1, "Socket: 0x%x\n", eax
1217
 
1218
        mcall   connect, [socketnum], [sockaddr], 18
1219
        test    eax, eax
1220
        jnz     .error2
1221
        DEBUGF  1, "Socket is now connected.\n"
1222
 
1223
; free allocated memory
1224
        push    [sockaddr]
1225
        call    [freeaddrinfo]
1226
 
1227
        mov     eax, [socketnum]
1228
        ret
1229
 
1230
  .error2:
1231
 
1232
; free allocated memory
1233
        push    [sockaddr]
1234
        call    [freeaddrinfo]
1235
 
1236
  .error1:
1237
        xor     eax, eax
1238
        ret
1239
 
1240
endp
1241
 
1242
 
4158 hidnplayr 1243
;;================================================================================================;;
1244
proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;;
1245
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1246
;? Split a given URL into hostname and pageaddr                                                   ;;
4158 hidnplayr 1247
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1248
;> URL = ptr to ASCIIZ URL                                                                        ;;
4158 hidnplayr 1249
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1250
;< eax = 0 (error) / ptr to ASCIIZ hostname                                                       ;;
1251
;< ebx = ptr to ASCIIZ pageaddr                                                                   ;;
4233 hidnplayr 1252
;< ecx = port number                                                                              ;;
4158 hidnplayr 1253
;;================================================================================================;;
1254
 
1255
locals
1256
        urlsize         dd ?
1257
        hostname        dd ?
1258
        pageaddr        dd ?
4233 hidnplayr 1259
        port            dd ?
4158 hidnplayr 1260
endl
1261
 
4161 hidnplayr 1262
        DEBUGF  1, "parsing URL: %s\n", [URL]
4158 hidnplayr 1263
 
1264
; remove any leading protocol text
1265
        mov     esi, [URL]
1266
        mov     ecx, URLMAXLEN
1267
        mov     ax, '//'
1268
  .loop1:
1269
        cmp     byte[esi], 0            ; end of URL?
1270
        je      .url_ok                 ; yep, so not found
1271
        cmp     [esi], ax
1272
        je      .skip_proto
1273
        inc     esi
1274
        dec     ecx
1275
        jnz     .loop1
4233 hidnplayr 1276
        jmp     .invalid
4158 hidnplayr 1277
 
1278
  .skip_proto:
1279
        inc     esi                     ; skip the two '/'
1280
        inc     esi
1281
        mov     [URL], esi              ; update pointer so it skips protocol
1282
        jmp     .loop1                  ; we still need to find the length of the URL
1283
 
1284
  .url_ok:
1285
        sub     esi, [URL]              ; calculate total length of URL
1286
        mov     [urlsize], esi
1287
 
1288
 
1289
; now look for page delimiter - it's a '/' character
1290
        mov     ecx, esi                ; URL length
1291
        mov     edi, [URL]
1292
        mov     al, '/'
1293
        repne   scasb
4161 hidnplayr 1294
        jne     @f
4158 hidnplayr 1295
        dec     edi                     ; return one char, '/' must be part of the pageaddr
1296
        inc     ecx                     ;
4161 hidnplayr 1297
  @@:
4158 hidnplayr 1298
        push    ecx edi                 ; remember the pointer and length of pageaddr
1299
 
4222 hidnplayr 1300
 
4233 hidnplayr 1301
; Create new buffer and put hostname in it.
4158 hidnplayr 1302
        mov     ecx, edi
1303
        sub     ecx, [URL]
1304
        inc     ecx                     ; we will add a 0 byte at the end
1305
        invoke  mem.alloc, ecx
1306
        or      eax, eax
1307
        jz      .no_mem
1308
 
1309
        mov     [hostname], eax         ; copy hostname to buffer
1310
        mov     edi, eax
1311
        mov     esi, [URL]
1312
        dec     ecx
1313
        rep     movsb
1314
        xor     al, al
1315
        stosb
1316
 
4233 hidnplayr 1317
; Check if user provided a port, and convert it if so.
1318
        mov     esi, [hostname]
1319
        mov     [port], 80              ; default port if user didnt provide one
1320
  .portloop:
1321
        lodsb
1322
        test    al, al
1323
        jz      .no_port
1324
        cmp     al, ':'
1325
        jne     .portloop
1326
 
1327
        push    esi
1328
        call    ascii_dec_ebx
1329
        pop     edi
1330
        cmp     byte[esi-1], 0
1331
        jne     .invalid
1332
        cmp     [proxyAddr], 0          ; remove port number from hostname
1333
        jne     @f                      ; unless when we are using proxy
1334
        mov     byte[edi-1], 0
1335
  @@:
1336
        test    ebx, ebx
1337
        je      .invalid
1338
        cmp     ebx, 0xffff
1339
        ja      .invalid
1340
        mov     [port], ebx
1341
  .no_port:
1342
 
1343
 
1344
; Did user provide a pageaddr?
4161 hidnplayr 1345
        mov     [pageaddr], str_slash   ; assume there is no pageaddr
4158 hidnplayr 1346
        pop     esi ecx
1347
        test    ecx, ecx
1348
        jz      .no_page
4233 hidnplayr 1349
 
1350
; Create new buffer and put pageaddr into it.
4158 hidnplayr 1351
        inc     ecx                     ; we will add a 0 byte at the end
1352
        invoke  mem.alloc, ecx
1353
        or      eax, eax
1354
        jz      .no_mem
1355
 
1356
        mov     [pageaddr], eax         ; copy pageaddr to buffer
1357
        mov     edi, eax
1358
        dec     ecx
1359
        rep     movsb
1360
        xor     al, al
1361
        stosb
4233 hidnplayr 1362
 
4158 hidnplayr 1363
  .no_page:
1364
        mov     eax, [hostname]
1365
        mov     ebx, [pageaddr]
4233 hidnplayr 1366
        mov     ecx, [port]
4158 hidnplayr 1367
 
1368
        DEBUGF  1, "hostname: %s\n", eax
1369
        DEBUGF  1, "pageaddr: %s\n", ebx
4221 hidnplayr 1370
        DEBUGF  1, "port: %u\n", ecx
4158 hidnplayr 1371
 
1372
        ret
1373
 
1374
  .no_mem:
4233 hidnplayr 1375
        DEBUGF  1, "Out of memory!\n"
4158 hidnplayr 1376
        xor     eax, eax
1377
        ret
1378
 
4233 hidnplayr 1379
  .invalid:
1380
        DEBUGF  1, "Invalid URL!\n"
1381
        xor     eax, eax
1382
        ret
1383
 
4158 hidnplayr 1384
endp
1385
 
1386
 
4233 hidnplayr 1387
 
1388
 
1389
 
4202 hidnplayr 1390
;;================================================================================================;;
4233 hidnplayr 1391
proc append_proxy_auth_header ;///////////////////////////////////////////////////////////////////;;
4202 hidnplayr 1392
;;------------------------------------------------------------------------------------------------;;
4233 hidnplayr 1393
;? Appends the proxy authentication header                                                        ;;
1394
;;------------------------------------------------------------------------------------------------;;
1395
;> /                                                                                              ;;
1396
;;------------------------------------------------------------------------------------------------;;
1397
;< /                                                                                              ;;
1398
;;================================================================================================;;
1399
        mov     esi, str_proxy_auth
1400
        mov     ecx, str_proxy_auth.length
1401
        rep     movsb
1402
; base64-encode string :
1403
        mov     esi, proxyUser
1404
 
1405
apah000:
1406
        lodsb
1407
        test    al, al
1408
        jz      apah001
1409
        call    encode_base64_byte
1410
        jmp     apah000
1411
 
1412
apah001:
1413
        mov     al, ':'
1414
        call    encode_base64_byte
1415
        mov     esi, proxyPassword
1416
 
1417
apah002:
1418
        lodsb
1419
        test    al, al
1420
        jz      apah003
1421
        call    encode_base64_byte
1422
        jmp     apah002
1423
 
1424
apah003:
1425
        call    encode_base64_final
1426
        ret
1427
 
1428
encode_base64_byte:
1429
        inc     ecx
1430
        shl     edx, 8
1431
        mov     dl, al
1432
        cmp     ecx, 3
1433
        je      ebb001
1434
        ret
1435
 
1436
ebb001:
1437
        shl     edx, 8
1438
        inc     ecx
1439
 
1440
ebb002:
1441
        rol     edx, 6
1442
        xor     eax, eax
1443
        xchg    al, dl
1444
        mov     al, [base64_table+eax]
1445
        stosb
1446
        loop    ebb002
1447
        ret
1448
 
1449
encode_base64_final:
1450
        mov     al, 0
1451
        test    ecx, ecx
1452
        jz      ebf000
1453
        call    encode_base64_byte
1454
        test    ecx, ecx
1455
        jz      ebf001
1456
        call    encode_base64_byte
1457
        mov     byte [edi-2], '='
1458
 
1459
ebf001:
1460
        mov     byte [edi-1], '='
1461
 
1462
ebf000:
1463
        ret
1464
 
1465
endp
1466
 
1467
 
1468
;;================================================================================================;;
1469
proc eax_ascii_dec ;//////////////////////////////////////////////////////////////////////////////;;
1470
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1471
;? Convert eax to ASCII decimal number                                                            ;;
1472
;;------------------------------------------------------------------------------------------------;;
1473
;> eax = number                                                                                   ;;
1474
;> edi = ptr where to write ASCII decimal number                                                  ;;
1475
;;------------------------------------------------------------------------------------------------;;
1476
;< /                                                                                              ;;
1477
;;================================================================================================;;
4158 hidnplayr 1478
 
4168 hidnplayr 1479
        push    -'0'
4167 hidnplayr 1480
        mov     ecx, 10
1481
  .loop:
1482
        xor     edx, edx
1483
        div     ecx
1484
        add     dl, '0'
4168 hidnplayr 1485
        push    edx
4167 hidnplayr 1486
        test    eax, eax
1487
        jnz     .loop
4158 hidnplayr 1488
 
4168 hidnplayr 1489
  .loop2:
1490
        pop     eax
1491
        add     al, '0'
1492
        jz      .done
1493
        stosb
1494
        jmp     .loop2
1495
  .done:
1496
 
4167 hidnplayr 1497
        ret
4158 hidnplayr 1498
 
4202 hidnplayr 1499
endp
4167 hidnplayr 1500
 
4202 hidnplayr 1501
 
4158 hidnplayr 1502
;;================================================================================================;;
4233 hidnplayr 1503
proc ascii_dec_ebx ;//////////////////////////////////////////////////////////////////////////////;;
1504
;;------------------------------------------------------------------------------------------------;;
1505
;? Convert ASCII decimal number to ebx                                                            ;;
1506
;;------------------------------------------------------------------------------------------------;;
1507
;> esi = ptr where to read ASCII decimal number                                                   ;;
1508
;;------------------------------------------------------------------------------------------------;;
1509
;> ebx = number                                                                                   ;;
1510
;;================================================================================================;;
1511
 
1512
        xor     eax, eax
1513
        xor     ebx, ebx
1514
  .loop:
1515
        lodsb
1516
        sub     al, '0'
1517
        jb      .done
1518
        cmp     al, 9
1519
        ja      .done
1520
        lea     ebx, [ebx + 4*ebx]
1521
        shl     ebx, 1
1522
        add     ebx, eax
1523
        jmp     .loop
1524
  .done:
1525
 
1526
        ret
1527
 
1528
endp
1529
 
1530
 
1531
;;================================================================================================;;
4158 hidnplayr 1532
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1533
;;================================================================================================;;
1534
;! Imported functions section                                                                     ;;
1535
;;================================================================================================;;
1536
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1537
;;================================================================================================;;
1538
 
1539
 
1540
align 16
1541
@IMPORT:
1542
 
1543
library \
1544
        libini, 'libini.obj', \
1545
        network, 'network.obj'
1546
 
1547
import  libini, \
1548
        ini.get_str, 'ini_get_str', \
1549
        ini.get_int, 'ini_get_int'
1550
 
1551
import  network,\
1552
        getaddrinfo, 'getaddrinfo',\
1553
        freeaddrinfo,  'freeaddrinfo',\
1554
        inet_ntoa, 'inet_ntoa'
1555
 
1556
;;===========================================================================;;
1557
;;///////////////////////////////////////////////////////////////////////////;;
1558
;;===========================================================================;;
1559
;! Exported functions section                                                ;;
1560
;;===========================================================================;;
1561
;;///////////////////////////////////////////////////////////////////////////;;
1562
;;===========================================================================;;
1563
 
1564
 
1565
align 4
1566
@EXPORT:
1567
export  \
1568
        lib_init                , 'lib_init'            , \
1569
        0x00010001              , 'version'             , \
1570
        HTTP_get                , 'get'                 , \
4167 hidnplayr 1571
        HTTP_head               , 'head'                , \
1572
        HTTP_post               , 'post'                , \
4222 hidnplayr 1573
        HTTP_find_header_field  , 'find_header_field'   , \
4205 hidnplayr 1574
        HTTP_process            , 'process'             , \
1575
        HTTP_free               , 'free'                , \
4209 hidnplayr 1576
        HTTP_stop               , 'stop'                , \
1577
        URI_escape              , 'escape'              , \
1578
        URI_unescape            , 'unescape'
4158 hidnplayr 1579
 
1580
;        HTTP_put                , 'put'                 , \
1581
;        HTTP_delete             , 'delete'              , \
1582
;        HTTP_trace              , 'trace'               , \
1583
;        HTTP_connect            , 'connect'             , \
1584
 
1585
 
1586
 
1587
section '.data' data readable writable align 16
1588
 
1589
inifile         db '/sys/settings/network.ini', 0
1590
 
1591
sec_proxy:
1592
key_proxy       db 'proxy', 0
1593
key_proxyport   db 'port', 0
1594
key_user        db 'user', 0
1595
key_password    db 'password', 0
1596
 
1597
str_http11      db ' HTTP/1.1', 13, 10, 'Host: '
1598
  .length       = $ - str_http11
4167 hidnplayr 1599
str_post_cl     db 13, 10, 'Content-Length: '
1600
  .length       = $ - str_post_cl
1601
str_post_ct     db 13, 10, 'Content-Type: '
1602
  .length       = $ - str_post_ct
4158 hidnplayr 1603
str_proxy_auth  db 13, 10, 'Proxy-Authorization: Basic '
1604
  .length       = $ - str_proxy_auth
4241 hidnplayr 1605
str_close       db 'User-Agent: KolibriOS libHTTP/1.0', 13, 10, 'Connection: Close', 13, 10, 13, 10
1606
  .length       = $ - str_close
4158 hidnplayr 1607
 
4233 hidnplayr 1608
str_http        db 'http://', 0
1609
 
4158 hidnplayr 1610
base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
1611
                db '0123456789+/'
1612
 
1613
str_cl          db 'content-length', 0
4161 hidnplayr 1614
str_slash       db '/', 0
4158 hidnplayr 1615
str_te          db 'transfer-encoding', 0
4167 hidnplayr 1616
str_get         db 'GET ', 0
1617
str_head        db 'HEAD ', 0
1618
str_post        db 'POST ', 0
4158 hidnplayr 1619
 
4209 hidnplayr 1620
bits_must_escape:
1621
dd      0xffffffff                                                      ; 00-1F
1622
dd      1 shl 0 + 1 shl 2 + 1 shl 3 + 1 shl 5 + 1 shl 28 + 1 shl 30     ; "#%<>
1623
dd      1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 30                       ;[\]^
1624
dd      1 shl 0 + 1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 31             ;`{|} DEL
1625
 
1626
dd      0xffffffff
1627
dd      0xffffffff
1628
dd      0xffffffff
1629
dd      0xffffffff
1630
 
1631
str_hex:
1632
db '0123456789ABCDEF'
1633
 
4158 hidnplayr 1634
include_debug_strings
1635
 
1636
; uninitialized data
1637
mem.alloc       dd ?
1638
mem.free        dd ?
1639
mem.realloc     dd ?
1640
dll.load        dd ?
1641
 
1642
proxyAddr       rb 256
1643
proxyUser       rb 256
1644
proxyPassword   rb 256
1645
proxyPort       dd ?