Subversion Repositories Kolibri OS

Rev

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

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