Subversion Repositories Kolibri OS

Rev

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

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