Subversion Repositories Kolibri OS

Rev

Rev 7971 | Rev 8570 | 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
 
8023 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
 
8023 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]
8023 hidnplayr 1028
        add     ebx, [buffersize]
7969 hidnplayr 1029
        cmp     [ebp + http_msg.write_ptr], ebx
1030
        jb      @f
1031
        DEBUGF  1, "Restarting at beginning of ring buffer\n"
8023 hidnplayr 1032
        mov     ebx, [buffersize]
1033
        sub     [ebp + http_msg.write_ptr], ebx
7969 hidnplayr 1034
  @@:
4690 hidnplayr 1035
        ; Header was already parsed and connection isnt chunked.
1036
        ; Update content_received
4168 hidnplayr 1037
        add     [ebp + http_msg.content_received], eax
4690 hidnplayr 1038
        ; If we received content-length parameter, check if we received all the data
4220 hidnplayr 1039
        test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
4690 hidnplayr 1040
        jz      @f
4217 hidnplayr 1041
        mov     eax, [ebp + http_msg.content_received]
1042
        cmp     eax, [ebp + http_msg.content_length]
4168 hidnplayr 1043
        jae     .got_all_data
4690 hidnplayr 1044
  @@:
1045
        cmp     [ebp + http_msg.buffer_length], 0
1046
        je      .buffer_full
1047
        ; Need more data
1048
        popa
1049
        xor     eax, eax
1050
        dec     eax
1051
        ret
4212 hidnplayr 1052
 
4690 hidnplayr 1053
  .buffer_full:
5537 hidnplayr 1054
        test    [ebp + http_msg.flags], FLAG_STREAM
5534 hidnplayr 1055
        jnz     .multibuff
4220 hidnplayr 1056
        mov     eax, [ebp + http_msg.write_ptr]
7512 hidnplayr 1057
        add     eax, [buffersize]
4541 hidnplayr 1058
        sub     eax, [ebp + http_msg.content_ptr]
1059
        invoke  mem.realloc, [ebp + http_msg.content_ptr], eax
4220 hidnplayr 1060
        or      eax, eax
4690 hidnplayr 1061
        jz      .err_no_ram
4541 hidnplayr 1062
        call    recalculate_pointers
7512 hidnplayr 1063
        push    [buffersize]
1064
        pop     [ebp + http_msg.buffer_length]
4690 hidnplayr 1065
        ; Need more data
1066
        popa
1067
        xor     eax, eax
1068
        dec     eax
1069
        ret
4220 hidnplayr 1070
 
5534 hidnplayr 1071
  .multibuff:
1072
        ; This buffer is full
1073
        popa
1074
        xor     eax, eax
1075
        ret
1076
 
4690 hidnplayr 1077
  .need_more_data_for_header:
1078
        cmp     [ebp + http_msg.buffer_length], 0
1079
        je      .err_header                     ; It's just too damn long!
1080
        ; Need more data
4162 hidnplayr 1081
        popa
1082
        xor     eax, eax
1083
        dec     eax
1084
        ret
4158 hidnplayr 1085
 
4162 hidnplayr 1086
  .need_more_data_chunked:
7969 hidnplayr 1087
; If we're using ring buffer, check we crossed the boundary
1088
        test    [ebp + http_msg.flags], FLAG_RING
1089
        jz      @f
1090
        mov     ebx, [ebp + http_msg.content_ptr]
8023 hidnplayr 1091
        add     ebx, [buffersize]
7969 hidnplayr 1092
        cmp     [ebp + http_msg.write_ptr], ebx
1093
        jb      @f
1094
        DEBUGF  1, "Restarting at beginning of ring buffer\n"
8023 hidnplayr 1095
        mov     ebx, [buffersize]
1096
        sub     [ebp + http_msg.write_ptr], ebx
7969 hidnplayr 1097
  @@:
4690 hidnplayr 1098
        ; We only got a partial chunk, or need more chunks, update content_received and request more data
4168 hidnplayr 1099
        add     [ebp + http_msg.content_received], eax
4158 hidnplayr 1100
        popa
1101
        xor     eax, eax
1102
        dec     eax
1103
        ret
1104
 
4162 hidnplayr 1105
  .got_all_data_chunked:
4690 hidnplayr 1106
        ; Woohoo, we got all the chunked data, calculate total number of bytes received.
4162 hidnplayr 1107
        mov     eax, [ebp + http_msg.chunk_ptr]
4541 hidnplayr 1108
        sub     eax, [ebp + http_msg.content_ptr]
4162 hidnplayr 1109
        mov     [ebp + http_msg.content_length], eax
4168 hidnplayr 1110
        mov     [ebp + http_msg.content_received], eax
4158 hidnplayr 1111
  .got_all_data:
4217 hidnplayr 1112
        DEBUGF  1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_received]
4205 hidnplayr 1113
        or      [ebp + http_msg.flags], FLAG_GOT_ALL_DATA
5769 hidnplayr 1114
        test    [ebp + http_msg.flags], FLAG_KEEPALIVE
1115
        jnz     @f
1116
        mcall   close, [ebp + http_msg.socket]
4205 hidnplayr 1117
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
5769 hidnplayr 1118
  @@:
4158 hidnplayr 1119
        popa
1120
        xor     eax, eax
1121
        ret
1122
 
4690 hidnplayr 1123
;--------------------------------------------------------------
1124
;
1125
; error handeling code begins here
1126
;
1127
 
4158 hidnplayr 1128
  .check_socket:
1129
        cmp     ebx, EWOULDBLOCK
4690 hidnplayr 1130
        jne     .err_socket
1131
        mcall   26, 9
1132
        sub     eax, [ebp + http_msg.timestamp]
1133
        cmp     eax, TIMEOUT
1134
        ja      .err_timeout
1135
        ; Need more data
1136
        popa
1137
        xor     eax, eax
1138
        dec     eax
1139
        ret
4158 hidnplayr 1140
 
4220 hidnplayr 1141
  .server_closed:
1142
        DEBUGF  1, "server closed connection, transfer complete?\n"
8023 hidnplayr 1143
        mcall   close, [ebp + http_msg.socket]
1144
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
4220 hidnplayr 1145
        test    [ebp + http_msg.flags], FLAG_GOT_HEADER
4690 hidnplayr 1146
        jz      .err_server_closed
4220 hidnplayr 1147
        test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
1148
        jz      .got_all_data
4690 hidnplayr 1149
  .err_server_closed:
4220 hidnplayr 1150
        pop     eax
5732 hidnplayr 1151
        DEBUGF  2, "ERROR: server closed connection unexpectedly\n"
4220 hidnplayr 1152
        or      [ebp + http_msg.flags], FLAG_TRANSFER_FAILED
4690 hidnplayr 1153
        jmp     .abort
4220 hidnplayr 1154
 
4690 hidnplayr 1155
  .err_header:
4203 hidnplayr 1156
        pop     eax
5732 hidnplayr 1157
        DEBUGF  2, "ERROR: invalid header\n"
4158 hidnplayr 1158
        or      [ebp + http_msg.flags], FLAG_INVALID_HEADER
4690 hidnplayr 1159
        jmp     .abort
4158 hidnplayr 1160
 
4690 hidnplayr 1161
  .err_no_ram:
5732 hidnplayr 1162
        DEBUGF  2, "ERROR: out of RAM\n"
4158 hidnplayr 1163
        or      [ebp + http_msg.flags], FLAG_NO_RAM
7969 hidnplayr 1164
        jmp     .abort  ; TODO: dont abort connection (requires rechecking all codepaths..)
4206 hidnplayr 1165
 
4690 hidnplayr 1166
  .err_timeout:
5732 hidnplayr 1167
        DEBUGF  2, "ERROR: timeout\n"
4690 hidnplayr 1168
        or      [ebp + http_msg.flags], FLAG_TIMEOUT_ERROR
1169
        jmp     .abort
1170
 
1171
  .err_socket:
5732 hidnplayr 1172
        DEBUGF  2, "ERROR: socket error %u\n", ebx
4206 hidnplayr 1173
        or      [ebp + http_msg.flags], FLAG_SOCKET_ERROR
4690 hidnplayr 1174
  .abort:
4205 hidnplayr 1175
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
1176
        mcall   close, [ebp + http_msg.socket]
4206 hidnplayr 1177
  .connection_closed:
7969 hidnplayr 1178
  .continue:
4158 hidnplayr 1179
        popa
1180
        xor     eax, eax
1181
        ret
1182
 
7969 hidnplayr 1183
  .need_more_space:
1184
        DEBUGF  1, "Buffer is full!\n"
1185
        and     [ebp + http_msg.flags], not FLAG_NEED_MORE_SPACE
1186
        popa
1187
        xor     eax, eax
1188
        ret
1189
 
4158 hidnplayr 1190
endp
1191
 
1192
 
4541 hidnplayr 1193
alloc_contentbuff:
4158 hidnplayr 1194
 
7969 hidnplayr 1195
        test    [ebp + http_msg.flags], FLAG_RING
1196
        jz      @f
1197
 
1198
        DEBUGF  1, "Allocating ring buffer\n"
1199
        mcall   68, 29, [buffersize]
1200
        or      eax, eax
1201
        jz      .no_ram
1202
        jmp     .allocated
1203
  @@:
1204
 
5537 hidnplayr 1205
        test    [ebp + http_msg.flags], FLAG_STREAM
1206
        jz      @f
7512 hidnplayr 1207
        mov     edx, [buffersize]
5537 hidnplayr 1208
  @@:
1209
 
4541 hidnplayr 1210
; Allocate content buffer
1211
        invoke  mem.alloc, edx
1212
        or      eax, eax
1213
        jz      .no_ram
4205 hidnplayr 1214
 
7969 hidnplayr 1215
  .allocated:
4541 hidnplayr 1216
        DEBUGF  1, "Content buffer allocated: 0x%x\n", eax
1217
 
1218
; Copy already received content into content buffer
1219
        mov     edi, eax
1220
        lea     esi, [ebp + http_msg.http_header]
1221
        add     esi, [ebp + http_msg.header_length]
1222
        mov     ecx, [ebp + http_msg.write_ptr]
1223
        sub     ecx, esi
1224
        mov     ebx, ecx
1225
        rep movsb
1226
 
1227
; Update pointers to point to new buffer
1228
        mov     [ebp + http_msg.content_ptr], eax
1229
        mov     [ebp + http_msg.content_received], ebx
1230
        sub     edx, ebx
1231
        mov     [ebp + http_msg.buffer_length], edx
1232
        add     eax, ebx
1233
        mov     [ebp + http_msg.write_ptr], eax
1234
 
1235
; Shrink header buffer
1236
        mov     eax, http_msg.http_header
1237
        add     eax, [ebp + http_msg.header_length]
1238
        invoke  mem.realloc, ebp, eax
1239
        or      eax, eax
7969 hidnplayr 1240
        ret
1241
 
4541 hidnplayr 1242
  .no_ram:
7969 hidnplayr 1243
        DEBUGF  2, "Error allocating content buffer!\n"
1244
        mov     [ebp + http_msg.buffer_length], 0       ;;;
4541 hidnplayr 1245
        ret
1246
 
1247
 
1248
 
1249
recalculate_pointers:
1250
 
1251
        sub     eax, [ebp + http_msg.content_ptr]
1252
        jz      .done
1253
        add     [ebp + http_msg.content_ptr], eax
1254
        add     [ebp + http_msg.write_ptr], eax
1255
        add     [ebp + http_msg.chunk_ptr], eax
1256
 
1257
  .done:
1258
        ret
1259
 
1260
 
1261
 
4158 hidnplayr 1262
;;================================================================================================;;
4996 hidnplayr 1263
proc HTTP_send identifier, dataptr, datalength ;//////////////////////////////////////////////////;;
4205 hidnplayr 1264
;;------------------------------------------------------------------------------------------------;;
4996 hidnplayr 1265
;? Send data to the server                                                                        ;;
4205 hidnplayr 1266
;;------------------------------------------------------------------------------------------------;;
1267
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
4996 hidnplayr 1268
;> dataptr      = pointer to data to be sent.                                                     ;;
1269
;> datalength   = length of data (in bytes) to be sent                                            ;;
4205 hidnplayr 1270
;;------------------------------------------------------------------------------------------------;;
4996 hidnplayr 1271
;< eax = number of bytes sent, -1 on error                                                        ;;
4205 hidnplayr 1272
;;================================================================================================;;
1273
 
4996 hidnplayr 1274
        push    ebx ecx edx esi edi
1275
        mov     edx, [identifier]
1276
        test    [edx + http_msg.flags], FLAG_CONNECTED
1277
        jz      .fail
1278
        mcall   send, [edx + http_msg.socket], [dataptr], [datalength], 0
1279
        pop     edi esi edx ecx ebx
4205 hidnplayr 1280
        ret
1281
 
4996 hidnplayr 1282
  .fail:
1283
        pop     edi esi edx ecx ebx
1284
        xor     eax, eax
1285
        dec     eax
4205 hidnplayr 1286
        ret
1287
 
1288
endp
1289
 
1290
 
1291
;;================================================================================================;;
4222 hidnplayr 1292
proc HTTP_find_header_field identifier, headername ;//////////////////////////////////////////////;;
4158 hidnplayr 1293
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1294
;? Find a header field in the received HTTP header                                                ;;
4996 hidnplayr 1295
;?                                                                                                ;;
1296
;? NOTE: this function returns a pointer which points into the original header data.              ;;
1297
;? The header field is terminated by a CR, LF, space or maybe even tab.                           ;;
1298
;? A free operation should not be operated on this pointer!                                       ;;
4158 hidnplayr 1299
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1300
;> identifier   = ptr to http_msg struct                                                          ;;
4996 hidnplayr 1301
;> headername   = ptr to ASCIIZ string containing field you want to find (must be in lowercase)   ;;
4158 hidnplayr 1302
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1303
;< eax = 0 (error) / ptr to content of the HTTP header field                                      ;;
4158 hidnplayr 1304
;;================================================================================================;;
1305
        push    ebx ecx edx esi edi
1306
 
1307
        DEBUGF  1, "Find header field: %s\n", [headername]
1308
 
1309
        mov     ebx, [identifier]
4202 hidnplayr 1310
        test    [ebx + http_msg.flags], FLAG_GOT_HEADER
1311
        jz      .fail
1312
 
4541 hidnplayr 1313
        lea     edx, [ebx + http_msg.http_header]
4158 hidnplayr 1314
        mov     ecx, edx
1315
        add     ecx, [ebx + http_msg.header_length]
1316
 
1317
  .restart:
1318
        mov     esi, [headername]
1319
        mov     edi, edx
1320
  .loop:
1321
        cmp     edi, ecx
1322
        jae     .fail
1323
        lodsb
1324
        scasb
1325
        je      .loop
1326
        test    al, al
1327
        jz      .done?
1328
  .next:
1329
        inc     edx
1330
        jmp     .restart
1331
 
1332
  .not_done:
1333
        inc     edi
1334
  .done?:
1335
        cmp     byte[edi-1], ':'
1336
        je      .almost_done
1337
        cmp     byte[edi-1], ' '
1338
        je      .not_done
1339
        cmp     byte[edi-1], 9  ; tab
1340
        je      .not_done
1341
 
1342
        jmp     .next
1343
 
1344
  .almost_done:                 ; FIXME: buffer overflow?
1345
        dec     edi
1346
        DEBUGF  1, "Found header field\n"
1347
  .spaceloop:
1348
        inc     edi
1349
        cmp     byte[edi], ' '
1350
        je      .spaceloop
1351
        cmp     byte[edi], 9    ; tab
1352
        je      .spaceloop
1353
 
1354
        mov     eax, edi
1355
        pop     edi esi edx ecx ebx
1356
        ret
1357
 
1358
  .fail:
7006 hidnplayr 1359
        DEBUGF  1, "Header field not found\n"
4158 hidnplayr 1360
        pop     edi esi edx ecx ebx
1361
        xor     eax, eax
1362
        ret
1363
 
1364
endp
1365
 
1366
 
1367
 
4209 hidnplayr 1368
;;================================================================================================;;
5534 hidnplayr 1369
proc HTTP_escape URI, length ;////////////////////////////////////////////////////////////////////;;
4209 hidnplayr 1370
;;------------------------------------------------------------------------------------------------;;
1371
;?                                                                                                ;;
1372
;;------------------------------------------------------------------------------------------------;;
5534 hidnplayr 1373
;> URI = ptr to ASCIIZ URI/data                                                                   ;;
1374
;> length = length of URI/data                                                                    ;;
4209 hidnplayr 1375
;;------------------------------------------------------------------------------------------------;;
4831 hidnplayr 1376
;< eax = 0 (error) / ptr to ASCIIZ URI/data                                                       ;;
1377
;< ebx = length of escaped URI/data                                                               ;;
4209 hidnplayr 1378
;;================================================================================================;;
4202 hidnplayr 1379
 
4848 hidnplayr 1380
        DEBUGF  1, "HTTP_escape: %s\n", [URI]
1381
 
4209 hidnplayr 1382
        pusha
4205 hidnplayr 1383
 
5534 hidnplayr 1384
        invoke  mem.alloc, URLMAXLEN            ; FIXME: use length provided by caller to guess final size.
4209 hidnplayr 1385
        test    eax, eax
1386
        jz      .error
7101 hidnplayr 1387
        mov     edx, URLMAXLEN-1                ; Remaining space in temp buffer minus one for 0 byte
4209 hidnplayr 1388
        mov     [esp + 7 * 4], eax              ; return ptr in eax
1389
        mov     esi, [URI]
1390
        mov     edi, eax
1391
        xor     ebx, ebx
1392
        xor     ecx, ecx
1393
  .loop:
1394
        lodsb
1395
        test    al, al
1396
        jz      .done
1397
 
1398
        mov     cl, al
1399
        and     cl, 0x1f
1400
        mov     bl, al
4831 hidnplayr 1401
        shr     bl, 3
1402
        and     bl, not 3
4209 hidnplayr 1403
        bt      dword[bits_must_escape + ebx], ecx
1404
        jc      .escape
1405
 
1406
        stosb
7101 hidnplayr 1407
        dec     edx
1408
        jnz     .loop
1409
        jmp     .out_of_space
4209 hidnplayr 1410
 
1411
  .escape:
7101 hidnplayr 1412
        sub     edx, 3
1413
        jbe     .out_of_space
4209 hidnplayr 1414
        mov     al, '%'
1415
        stosb
1416
        mov     bl, byte[esi-1]
1417
        shr     bl, 4
1418
        mov     al, byte[str_hex + ebx]
1419
        stosb
1420
        mov     bl, byte[esi-1]
1421
        and     bl, 0x0f
1422
        mov     al, byte[str_hex + ebx]
1423
        stosb
1424
        jmp     .loop
1425
 
1426
 
7101 hidnplayr 1427
  .out_of_space:
1428
        DEBUGF  2, "ERROR: buffer too small!\n"
1429
 
4209 hidnplayr 1430
  .done:
7101 hidnplayr 1431
        xor     al, al
4209 hidnplayr 1432
        stosb
4831 hidnplayr 1433
        sub     edi, [esp + 7 * 4]
1434
        dec     edi
1435
        mov     [esp + 4 * 4], edi
4209 hidnplayr 1436
 
1437
        popa
4848 hidnplayr 1438
        DEBUGF  1, "escaped URL: %s\n", eax
4209 hidnplayr 1439
        ret
1440
 
1441
  .error:
5732 hidnplayr 1442
        DEBUGF  2, "ERROR: out of RAM!\n"
4209 hidnplayr 1443
        popa
1444
        xor     eax, eax
1445
        ret
1446
 
1447
endp
1448
 
1449
 
1450
 
4167 hidnplayr 1451
;;================================================================================================;;
5534 hidnplayr 1452
proc HTTP_unescape URI, length ;//////////////////////////////////////////////////////////////////;;
4209 hidnplayr 1453
;;------------------------------------------------------------------------------------------------;;
1454
;?                                                                                                ;;
1455
;;------------------------------------------------------------------------------------------------;;
1456
;> URI = ptr to ASCIIZ URI                                                                        ;;
1457
;;------------------------------------------------------------------------------------------------;;
1458
;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
1459
;;================================================================================================;;
1460
 
4848 hidnplayr 1461
        DEBUGF  1, "HTTP_unescape: %s\n", [URI]
4209 hidnplayr 1462
        pusha
1463
 
5534 hidnplayr 1464
        invoke  mem.alloc, URLMAXLEN            ; FIXME: use length provided by caller
4209 hidnplayr 1465
        test    eax, eax
1466
        jz      .error
7101 hidnplayr 1467
        mov     edx, URLMAXLEN-1                ; Remaining space in temp buffer minus one for 0 byte
4209 hidnplayr 1468
        mov     [esp + 7 * 4], eax              ; return ptr in eax
1469
        mov     esi, [URI]
1470
        mov     edi, eax
1471
  .loop:
1472
        lodsb
1473
        test    al, al
1474
        jz      .done
1475
        cmp     al, '%'
1476
        je      .unescape
1477
        stosb
7101 hidnplayr 1478
        dec     edx
1479
        jnz     .loop
1480
        jmp     .out_of_space
4209 hidnplayr 1481
 
1482
  .unescape:
1483
        xor     ebx, ebx
1484
        xor     ecx, ecx
1485
  .unescape_nibble:
1486
        lodsb
1487
        sub     al, '0'
1488
        jb      .fail
1489
        cmp     al, 9
1490
        jbe     .nibble_ok
1491
        sub     al, 'A' - '0' - 10
1492
        jb      .fail
1493
        cmp     al, 15
1494
        jbe     .nibble_ok
1495
        sub     al, 'a' - 'A'
1496
        cmp     al, 15
1497
        ja      .fail
1498
  .nibble_ok:
1499
        shl     bl, 8
1500
        or      bl, al
1501
        dec     ecx
1502
        jc      .unescape_nibble
1503
        mov     al, bl
1504
        stosb
7101 hidnplayr 1505
        dec     edx
1506
        jnz     .loop
1507
        jmp     .out_of_space
4209 hidnplayr 1508
 
1509
  .fail:
5732 hidnplayr 1510
        DEBUGF  2, "ERROR: invalid URI!\n"
4209 hidnplayr 1511
        jmp     .loop
1512
 
7101 hidnplayr 1513
  .out_of_space:
1514
        DEBUGF  2, "ERROR: buffer too small!\n"
1515
 
4209 hidnplayr 1516
  .done:
7101 hidnplayr 1517
        xor     al, al
4209 hidnplayr 1518
        stosb
1519
        popa
4848 hidnplayr 1520
        DEBUGF  1, "unescaped URL: %s\n", eax
4209 hidnplayr 1521
        ret
1522
 
1523
  .error:
5732 hidnplayr 1524
        DEBUGF  2, "ERROR: out of RAM!\n"
4209 hidnplayr 1525
        popa
1526
        xor     eax, eax
1527
        ret
1528
 
1529
endp
1530
 
1531
 
1532
 
1533
 
1534
 
1535
;;================================================================================================;;
4202 hidnplayr 1536
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1537
;;================================================================================================;;
1538
;! Internal procedures section                                                                    ;;
4220 hidnplayr 1539
;;                                                                                                ;;
1540
;; NOTICE: These procedures do not follow stdcall conventions and thus may destroy any register.  ;;
4202 hidnplayr 1541
;;================================================================================================;;
1542
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1543
;;================================================================================================;;
1544
 
1545
 
1546
 
1547
 
1548
;;================================================================================================;;
4167 hidnplayr 1549
proc open_connection hostname, port ;/////////////////////////////////////////////////////////////;;
1550
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1551
;? Connects to a HTTP server                                                                      ;;
4167 hidnplayr 1552
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1553
;> hostname     = ptr to ASCIIZ hostname                                                          ;;
1554
;> port         = port (x86 byte order)                                                           ;;
4167 hidnplayr 1555
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1556
;< eax = 0 (error) / socketnum                                                                    ;;
4167 hidnplayr 1557
;;================================================================================================;;
4158 hidnplayr 1558
 
4167 hidnplayr 1559
locals
1560
        sockaddr        dd ?
1561
        socketnum       dd ?
1562
endl
1563
 
4233 hidnplayr 1564
        cmp     [proxyAddr], 0
1565
        je      .no_proxy
1566
 
1567
        mov     [hostname], proxyAddr
1568
 
1569
        push    [proxyPort]
1570
        pop     [port]
1571
  .no_proxy:
1572
 
4167 hidnplayr 1573
; Resolve the hostname
1574
        DEBUGF  1, "Resolving hostname\n"
1575
        push    esp     ; reserve stack place
6921 hidnplayr 1576
        invoke  getaddrinfo, [hostname], 0, 0, esp
4167 hidnplayr 1577
        pop     esi
1578
        test    eax, eax
1579
        jnz     .error1
1580
 
1581
; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct
5904 hidnplayr 1582
        push    esi     ; for freeaddrinfo
4167 hidnplayr 1583
        mov     esi, [esi + addrinfo.ai_addr]
1584
        mov     [sockaddr], esi
1585
        mov     eax, [esi + sockaddr_in.sin_addr]
1586
        test    eax, eax
1587
        jz      .error2
1588
 
1589
        DEBUGF  1, "Server ip=%u.%u.%u.%u\n", \
1590
        [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \
1591
        [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1
1592
 
1593
        mov     [esi + sockaddr_in.sin_family], AF_INET4
1594
        mov     eax, [port]
1595
        xchg    al, ah
1596
        mov     [esi + sockaddr_in.sin_port], ax
1597
 
6921 hidnplayr 1598
; Open a new TCP socket
4167 hidnplayr 1599
        mcall   socket, AF_INET4, SOCK_STREAM, 0
1600
        test    eax, eax
6921 hidnplayr 1601
        jz      .error3
4167 hidnplayr 1602
        mov     [socketnum], eax
1603
        DEBUGF  1, "Socket: 0x%x\n", eax
1604
 
6921 hidnplayr 1605
; Connect to the server
4167 hidnplayr 1606
        mcall   connect, [socketnum], [sockaddr], 18
1607
        test    eax, eax
6921 hidnplayr 1608
        jnz     .error3
4167 hidnplayr 1609
        DEBUGF  1, "Socket is now connected.\n"
1610
 
6921 hidnplayr 1611
        invoke  freeaddrinfo            ; Free allocated memory
4167 hidnplayr 1612
        mov     eax, [socketnum]
1613
        ret
1614
 
6921 hidnplayr 1615
  .error3:
1616
        DEBUGF  2, "Could not connect to the remote server\n"
1617
        invoke  freeaddrinfo            ; Free allocated memory
1618
        xor     eax, eax
1619
        ret
1620
 
4167 hidnplayr 1621
  .error2:
6921 hidnplayr 1622
        DEBUGF  2, "Resolving hostname failed\n"
1623
        invoke  freeaddrinfo            ; Free allocated memory
1624
        xor     eax, eax
1625
        ret
1626
 
4167 hidnplayr 1627
  .error1:
7009 ashmew2 1628
        DEBUGF  2, "Contacting DNS server failed with EAI code: %x\n", eax
4167 hidnplayr 1629
        xor     eax, eax
1630
        ret
1631
 
1632
endp
1633
 
1634
 
4158 hidnplayr 1635
;;================================================================================================;;
1636
proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;;
1637
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1638
;? Split a given URL into hostname and pageaddr                                                   ;;
4158 hidnplayr 1639
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1640
;> URL = ptr to ASCIIZ URL                                                                        ;;
4158 hidnplayr 1641
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1642
;< eax = 0 (error) / ptr to ASCIIZ hostname                                                       ;;
1643
;< ebx = ptr to ASCIIZ pageaddr                                                                   ;;
4233 hidnplayr 1644
;< ecx = port number                                                                              ;;
4158 hidnplayr 1645
;;================================================================================================;;
1646
 
1647
locals
1648
        urlsize         dd ?
1649
        hostname        dd ?
1650
        pageaddr        dd ?
4233 hidnplayr 1651
        port            dd ?
4158 hidnplayr 1652
endl
1653
 
4161 hidnplayr 1654
        DEBUGF  1, "parsing URL: %s\n", [URL]
4158 hidnplayr 1655
 
1656
; remove any leading protocol text
4983 hidnplayr 1657
        mov     edi, [URL]
4158 hidnplayr 1658
        mov     ecx, URLMAXLEN
1659
        mov     ax, '//'
1660
  .loop1:
4983 hidnplayr 1661
        cmp     byte[edi], 0            ; end of URL?
4158 hidnplayr 1662
        je      .url_ok                 ; yep, so not found
4983 hidnplayr 1663
        cmp     [edi], ax
4158 hidnplayr 1664
        je      .skip_proto
4983 hidnplayr 1665
        inc     edi
4158 hidnplayr 1666
        dec     ecx
1667
        jnz     .loop1
4233 hidnplayr 1668
        jmp     .invalid
4158 hidnplayr 1669
 
1670
  .skip_proto:
4983 hidnplayr 1671
        inc     edi                     ; skip the two '/'
1672
        inc     edi
1673
        mov     [URL], edi              ; update pointer so it skips protocol
4158 hidnplayr 1674
 
4983 hidnplayr 1675
; Find the trailing 0 byte
1676
        xor     al, al
1677
        repne   scasb
1678
        jne     .invalid                ; ecx reached 0 before we reached end of string
1679
 
4158 hidnplayr 1680
  .url_ok:
4983 hidnplayr 1681
        sub     edi, [URL]              ; calculate total length of URL
1682
        mov     [urlsize], edi
4158 hidnplayr 1683
 
1684
; now look for page delimiter - it's a '/' character
4983 hidnplayr 1685
        mov     ecx, edi                ; URL length
4158 hidnplayr 1686
        mov     edi, [URL]
1687
        mov     al, '/'
1688
        repne   scasb
4161 hidnplayr 1689
        jne     @f
4158 hidnplayr 1690
        dec     edi                     ; return one char, '/' must be part of the pageaddr
1691
        inc     ecx                     ;
4161 hidnplayr 1692
  @@:
4158 hidnplayr 1693
        push    ecx edi                 ; remember the pointer and length of pageaddr
1694
 
4222 hidnplayr 1695
 
4233 hidnplayr 1696
; Create new buffer and put hostname in it.
4158 hidnplayr 1697
        mov     ecx, edi
1698
        sub     ecx, [URL]
1699
        inc     ecx                     ; we will add a 0 byte at the end
1700
        invoke  mem.alloc, ecx
1701
        or      eax, eax
1702
        jz      .no_mem
1703
 
1704
        mov     [hostname], eax         ; copy hostname to buffer
1705
        mov     edi, eax
1706
        mov     esi, [URL]
1707
        dec     ecx
1708
        rep     movsb
1709
        xor     al, al
1710
        stosb
1711
 
4233 hidnplayr 1712
; Check if user provided a port, and convert it if so.
1713
        mov     esi, [hostname]
1714
        mov     [port], 80              ; default port if user didnt provide one
1715
  .portloop:
1716
        lodsb
1717
        test    al, al
1718
        jz      .no_port
1719
        cmp     al, ':'
1720
        jne     .portloop
1721
 
1722
        push    esi
1723
        call    ascii_dec_ebx
1724
        pop     edi
1725
        cmp     byte[esi-1], 0
1726
        jne     .invalid
1727
        cmp     [proxyAddr], 0          ; remove port number from hostname
1728
        jne     @f                      ; unless when we are using proxy
1729
        mov     byte[edi-1], 0
1730
  @@:
1731
        test    ebx, ebx
1732
        je      .invalid
1733
        cmp     ebx, 0xffff
1734
        ja      .invalid
1735
        mov     [port], ebx
1736
  .no_port:
1737
 
1738
 
1739
; Did user provide a pageaddr?
4161 hidnplayr 1740
        mov     [pageaddr], str_slash   ; assume there is no pageaddr
4158 hidnplayr 1741
        pop     esi ecx
1742
        test    ecx, ecx
1743
        jz      .no_page
4233 hidnplayr 1744
 
1745
; Create new buffer and put pageaddr into it.
4158 hidnplayr 1746
        inc     ecx                     ; we will add a 0 byte at the end
1747
        invoke  mem.alloc, ecx
1748
        or      eax, eax
1749
        jz      .no_mem
1750
 
1751
        mov     [pageaddr], eax         ; copy pageaddr to buffer
1752
        mov     edi, eax
1753
        dec     ecx
1754
        rep     movsb
1755
        xor     al, al
1756
        stosb
4233 hidnplayr 1757
 
4158 hidnplayr 1758
  .no_page:
1759
        mov     eax, [hostname]
1760
        mov     ebx, [pageaddr]
4233 hidnplayr 1761
        mov     ecx, [port]
4158 hidnplayr 1762
 
1763
        DEBUGF  1, "hostname: %s\n", eax
1764
        DEBUGF  1, "pageaddr: %s\n", ebx
4221 hidnplayr 1765
        DEBUGF  1, "port: %u\n", ecx
4158 hidnplayr 1766
 
1767
        ret
1768
 
1769
  .no_mem:
5732 hidnplayr 1770
        DEBUGF  2, "Out of memory!\n"
4158 hidnplayr 1771
        xor     eax, eax
1772
        ret
1773
 
4233 hidnplayr 1774
  .invalid:
5732 hidnplayr 1775
        DEBUGF  2, "Invalid URL!\n"
4233 hidnplayr 1776
        xor     eax, eax
1777
        ret
1778
 
4158 hidnplayr 1779
endp
1780
 
1781
 
4233 hidnplayr 1782
 
1783
 
1784
 
4202 hidnplayr 1785
;;================================================================================================;;
4233 hidnplayr 1786
proc append_proxy_auth_header ;///////////////////////////////////////////////////////////////////;;
4202 hidnplayr 1787
;;------------------------------------------------------------------------------------------------;;
4233 hidnplayr 1788
;? Appends the proxy authentication header                                                        ;;
1789
;;------------------------------------------------------------------------------------------------;;
1790
;> /                                                                                              ;;
1791
;;------------------------------------------------------------------------------------------------;;
1792
;< /                                                                                              ;;
1793
;;================================================================================================;;
1794
        mov     esi, str_proxy_auth
1795
        mov     ecx, str_proxy_auth.length
1796
        rep     movsb
1797
; base64-encode string :
1798
        mov     esi, proxyUser
1799
 
1800
apah000:
1801
        lodsb
1802
        test    al, al
1803
        jz      apah001
1804
        call    encode_base64_byte
1805
        jmp     apah000
1806
 
1807
apah001:
1808
        mov     al, ':'
1809
        call    encode_base64_byte
1810
        mov     esi, proxyPassword
1811
 
1812
apah002:
1813
        lodsb
1814
        test    al, al
1815
        jz      apah003
1816
        call    encode_base64_byte
1817
        jmp     apah002
1818
 
1819
apah003:
1820
        call    encode_base64_final
1821
        ret
1822
 
1823
encode_base64_byte:
1824
        inc     ecx
1825
        shl     edx, 8
1826
        mov     dl, al
1827
        cmp     ecx, 3
1828
        je      ebb001
1829
        ret
1830
 
1831
ebb001:
1832
        shl     edx, 8
1833
        inc     ecx
1834
 
1835
ebb002:
1836
        rol     edx, 6
1837
        xor     eax, eax
1838
        xchg    al, dl
1839
        mov     al, [base64_table+eax]
1840
        stosb
1841
        loop    ebb002
1842
        ret
1843
 
1844
encode_base64_final:
1845
        mov     al, 0
1846
        test    ecx, ecx
1847
        jz      ebf000
1848
        call    encode_base64_byte
1849
        test    ecx, ecx
1850
        jz      ebf001
1851
        call    encode_base64_byte
1852
        mov     byte [edi-2], '='
1853
 
1854
ebf001:
1855
        mov     byte [edi-1], '='
1856
 
1857
ebf000:
1858
        ret
1859
 
1860
endp
1861
 
1862
 
1863
;;================================================================================================;;
1864
proc eax_ascii_dec ;//////////////////////////////////////////////////////////////////////////////;;
1865
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1866
;? Convert eax to ASCII decimal number                                                            ;;
1867
;;------------------------------------------------------------------------------------------------;;
1868
;> eax = number                                                                                   ;;
1869
;> edi = ptr where to write ASCII decimal number                                                  ;;
1870
;;------------------------------------------------------------------------------------------------;;
1871
;< /                                                                                              ;;
1872
;;================================================================================================;;
4158 hidnplayr 1873
 
4168 hidnplayr 1874
        push    -'0'
4167 hidnplayr 1875
        mov     ecx, 10
1876
  .loop:
1877
        xor     edx, edx
1878
        div     ecx
4168 hidnplayr 1879
        push    edx
4167 hidnplayr 1880
        test    eax, eax
1881
        jnz     .loop
4158 hidnplayr 1882
 
4168 hidnplayr 1883
  .loop2:
1884
        pop     eax
1885
        add     al, '0'
1886
        jz      .done
1887
        stosb
1888
        jmp     .loop2
1889
  .done:
1890
 
4167 hidnplayr 1891
        ret
4158 hidnplayr 1892
 
4202 hidnplayr 1893
endp
4167 hidnplayr 1894
 
4202 hidnplayr 1895
 
4158 hidnplayr 1896
;;================================================================================================;;
4233 hidnplayr 1897
proc ascii_dec_ebx ;//////////////////////////////////////////////////////////////////////////////;;
1898
;;------------------------------------------------------------------------------------------------;;
1899
;? Convert ASCII decimal number to ebx                                                            ;;
1900
;;------------------------------------------------------------------------------------------------;;
1901
;> esi = ptr where to read ASCII decimal number                                                   ;;
1902
;;------------------------------------------------------------------------------------------------;;
1903
;> ebx = number                                                                                   ;;
1904
;;================================================================================================;;
1905
 
1906
        xor     eax, eax
1907
        xor     ebx, ebx
1908
  .loop:
1909
        lodsb
1910
        sub     al, '0'
1911
        jb      .done
1912
        cmp     al, 9
1913
        ja      .done
1914
        lea     ebx, [ebx + 4*ebx]
1915
        shl     ebx, 1
1916
        add     ebx, eax
1917
        jmp     .loop
1918
  .done:
1919
 
1920
        ret
1921
 
1922
endp
1923
 
1924
 
1925
;;================================================================================================;;
4158 hidnplayr 1926
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1927
;;================================================================================================;;
1928
;! Imported functions section                                                                     ;;
1929
;;================================================================================================;;
1930
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1931
;;================================================================================================;;
1932
 
1933
 
1934
align 16
1935
@IMPORT:
1936
 
1937
library \
1938
        libini, 'libini.obj', \
1939
        network, 'network.obj'
1940
 
1941
import  libini, \
1942
        ini.get_str, 'ini_get_str', \
1943
        ini.get_int, 'ini_get_int'
1944
 
1945
import  network,\
1946
        getaddrinfo, 'getaddrinfo',\
1947
        freeaddrinfo,  'freeaddrinfo',\
1948
        inet_ntoa, 'inet_ntoa'
1949
 
1950
;;===========================================================================;;
1951
;;///////////////////////////////////////////////////////////////////////////;;
1952
;;===========================================================================;;
1953
;! Exported functions section                                                ;;
1954
;;===========================================================================;;
1955
;;///////////////////////////////////////////////////////////////////////////;;
1956
;;===========================================================================;;
1957
 
1958
 
4996 hidnplayr 1959
HTTP_stop = HTTP_disconnect
1960
HTTP_process = HTTP_receive
1961
 
4158 hidnplayr 1962
align 4
1963
@EXPORT:
1964
export  \
1965
        lib_init                , 'lib_init'            , \
1966
        0x00010001              , 'version'             , \
7512 hidnplayr 1967
        HTTP_buffersize_get     , 'buffersize_get'      , \
1968
        HTTP_buffersize_set     , 'buffersize_set'      , \
4158 hidnplayr 1969
        HTTP_get                , 'get'                 , \
4167 hidnplayr 1970
        HTTP_head               , 'head'                , \
1971
        HTTP_post               , 'post'                , \
4222 hidnplayr 1972
        HTTP_find_header_field  , 'find_header_field'   , \
4996 hidnplayr 1973
        HTTP_process            , 'process'             , \    ; To be removed
1974
        HTTP_send               , 'send'                , \
1975
        HTTP_receive            , 'receive'             , \
1976
        HTTP_disconnect         , 'disconnect'          , \
4205 hidnplayr 1977
        HTTP_free               , 'free'                , \
4996 hidnplayr 1978
        HTTP_stop               , 'stop'                , \    ; To be removed
4831 hidnplayr 1979
        HTTP_escape             , 'escape'              , \
1980
        HTTP_unescape           , 'unescape'
4158 hidnplayr 1981
;        HTTP_put                , 'put'                 , \
1982
;        HTTP_delete             , 'delete'              , \
1983
;        HTTP_trace              , 'trace'               , \
1984
;        HTTP_connect            , 'connect'             , \
1985
 
1986
 
1987
 
1988
section '.data' data readable writable align 16
1989
 
1990
inifile         db '/sys/settings/network.ini', 0
1991
 
1992
sec_proxy:
1993
key_proxy       db 'proxy', 0
1994
key_proxyport   db 'port', 0
1995
key_user        db 'user', 0
1996
key_password    db 'password', 0
1997
 
1998
str_http11      db ' HTTP/1.1', 13, 10, 'Host: '
1999
  .length       = $ - str_http11
4167 hidnplayr 2000
str_post_cl     db 13, 10, 'Content-Length: '
2001
  .length       = $ - str_post_cl
2002
str_post_ct     db 13, 10, 'Content-Type: '
2003
  .length       = $ - str_post_ct
4158 hidnplayr 2004
str_proxy_auth  db 13, 10, 'Proxy-Authorization: Basic '
2005
  .length       = $ - str_proxy_auth
7296 hidnplayr 2006
str_close       db 'User-Agent: KolibriOS libHTTP/1.1', 13, 10, 'Connection: close', 13, 10, 13, 10
4241 hidnplayr 2007
  .length       = $ - str_close
7296 hidnplayr 2008
str_keep        db 'User-Agent: KolibriOS libHTTP/1.1', 13, 10, 'Connection: keep-alive', 13, 10, 13, 10
5769 hidnplayr 2009
  .length       = $ - str_keep
4158 hidnplayr 2010
 
4233 hidnplayr 2011
str_http        db 'http://', 0
2012
 
4158 hidnplayr 2013
base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
2014
                db '0123456789+/'
2015
 
2016
str_cl          db 'content-length', 0
4161 hidnplayr 2017
str_slash       db '/', 0
4158 hidnplayr 2018
str_te          db 'transfer-encoding', 0
4167 hidnplayr 2019
str_get         db 'GET ', 0
2020
str_head        db 'HEAD ', 0
2021
str_post        db 'POST ', 0
4158 hidnplayr 2022
 
4209 hidnplayr 2023
bits_must_escape:
2024
dd      0xffffffff                                                      ; 00-1F
2025
dd      1 shl 0 + 1 shl 2 + 1 shl 3 + 1 shl 5 + 1 shl 28 + 1 shl 30     ; "#%<>
2026
dd      1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 30                       ;[\]^
2027
dd      1 shl 0 + 1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 31             ;`{|} DEL
2028
 
2029
dd      0xffffffff
2030
dd      0xffffffff
2031
dd      0xffffffff
2032
dd      0xffffffff
2033
 
2034
str_hex:
2035
db '0123456789ABCDEF'
2036
 
7512 hidnplayr 2037
buffersize      dd BUFFERSIZE
2038
 
4158 hidnplayr 2039
include_debug_strings
2040
 
2041
; uninitialized data
2042
mem.alloc       dd ?
2043
mem.free        dd ?
2044
mem.realloc     dd ?
2045
dll.load        dd ?
2046
 
2047
proxyAddr       rb 256
2048
proxyUser       rb 256
2049
proxyPassword   rb 256
2050
proxyPort       dd ?