Subversion Repositories Kolibri OS

Rev

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

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