Subversion Repositories Kolibri OS

Rev

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