forked from gigablast/open-source-search-engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HttpServer.cpp
3811 lines (3425 loc) · 123 KB
/
HttpServer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "gb-include.h"
#include "HttpServer.h"
#include "Pages.h"
#include "Collectiondb.h"
#include "HashTable.h"
#include "Stats.h"
#include "Users.h"
#include "XmlDoc.h" // gbzip
#include "UdpServer.h"
#include "Proxy.h"
#include "PageCrawlBot.h"
// a global class extern'd in .h file
HttpServer g_httpServer;
// this is defined in PageEvents.cpp
//bool sendPageSiteMap ( TcpSocket *s , HttpRequest *r ) ;
//bool sendPageApi ( TcpSocket *s , HttpRequest *r ) ;
bool sendPageAnalyze ( TcpSocket *s , HttpRequest *r ) ;
bool sendPagePretty ( TcpSocket *s , HttpRequest *r , char *filename ,
char *tabName ) ;
// we get like 100k submissions a day!!!
static HashTable s_htable;
static bool s_init = false;
static int32_t s_lastTime = 0;
// declare our C functions
static void requestHandlerWrapper ( TcpSocket *s ) ;
static void cleanUp ( void *state , TcpSocket *s ) ;
static void getMsgPieceWrapper ( int fd , void *state /*sockDesc*/ );
static void getSSLMsgPieceWrapper ( int fd , void *state /*sockDesc*/ );
// we now use the socket descriptor as state info for TcpServer instead of
// the TcpSocket ptr in case it got destroyed
static int32_t getMsgPiece ( TcpSocket *s );
static void gotDocWrapper ( void *state, TcpSocket *s );
static void handleRequestfd ( UdpSlot *slot , int32_t niceness ) ;
//bool sendPageAbout ( TcpSocket *s , HttpRequest *r , char *path ) ;
static int32_t s_numOutgoingSockets = 0;
// reset the tcp servers
void HttpServer::reset() {
m_tcp.reset();
m_ssltcp.reset();
s_htable.reset();
s_numOutgoingSockets = 0;
}
bool HttpServer::init ( int16_t port,
int16_t sslPort,
void handlerWrapper( TcpSocket *s )) {
// our mime table that maps a file extension to a content type
HttpMime mm;
if ( ! mm.init() ) return false;
// make it essentially infinite
//m_maxOpenSockets = 1000000;
//well, not infinite
//m_maxOpenSockets = g_conf.m_httpMaxSockets;
m_uncompressedBytes = m_bytesDownloaded = 1;
//if we haven't been given the handlerwrapper, use default
//used only by proxy right now
// qatest sets up a client-only httpserver, so don't set a
// handlerWrapper if no listening port
if (!handlerWrapper && (port || sslPort))
handlerWrapper = requestHandlerWrapper;
if ( ! g_udpServer.registerHandler ( 0xfd , handleRequestfd ) )
return false;
// set our base TcpServer class
if ( ! m_tcp.init( *handlerWrapper ,
getMsgSize ,
getMsgPiece ,
port ,
//&g_conf.m_httpMaxSockets ) ) return false;
&g_conf.m_httpMaxSockets ) ) return false;
//g_conf.m_httpMaxReadBufSize ,
//g_conf.m_httpMaxSendBufSize ) ) return false;
// set our secure TcpServer class
if ( ! m_ssltcp.init ( handlerWrapper,
getMsgSize,
getMsgPiece,
sslPort,
&g_conf.m_httpsMaxSockets,
true ) ) {
// this was required for communicating with an email alert
// web server, but no longer do i use them
//return false;
// don't break, just log and don't do SSL
log ( "https: SSL Server Failed To Init, Continuing..." );
m_ssltcp.reset();
}
// log an innocent msg
log(LOG_INIT,"http: Listening on TCP port %i with sd=%i",
port, m_tcp.m_sock );
// log for https
if (m_ssltcp.m_ready)
log(LOG_INIT,"https: Listening on TCP port %i with sd=%i",
sslPort, m_ssltcp.m_sock );
return true;
}
// . get a url's document
// . returns false if blocked, true otherwise
// . sets g_errno on error
// . IMPORTANT: we free doc/docLen, so NULLify s->m_readBuf if you want it
// . IMPORTANT: same goes for s->m_sendBuf
// . timeout in milliseconds since no read OR no write
// . proxyIp is 0 if we don't have one
bool HttpServer::getDoc ( char *url ,
int32_t ip ,
int32_t offset ,
int32_t size ,
time_t ifModifiedSince ,
void *state ,
void (* callback)( void *state , TcpSocket *s ) ,
int32_t timeout ,
int32_t proxyIp ,
int16_t proxyPort,
int32_t maxTextDocLen ,
int32_t maxOtherDocLen ,
char *userAgent ,
//bool respectDownloadLimit ,
char *proto ,
bool doPost ,
char *cookie ,
char *additionalHeader ,
char *fullRequest ,
char *postContent ,
char *proxyUsernamePwdAuth ) {
// sanity
if ( ip == -1 )
log("http: you probably didn't mean to set ip=-1 did you? "
"try setting to 0.");
// ignore if -1 as well
if ( proxyIp == -1 ) proxyIp = 0;
//log(LOG_WARN, "http: get doc %s", url->getUrl());
// use the HttpRequest class
HttpRequest r;
// set default port
int32_t defPort = 80;
// check for a secured site
TcpServer *tcp = &m_tcp;
bool urlIsHttps = false;
if ( url && strncasecmp(url, "https://", 8) == 0 ) {
urlIsHttps = true;
defPort = 443;
}
// if we are using gigablast as a squid proxy then the
// "fullRequest" and the url will be like "CONNECT foo.com:443 HTT..."
// and it is an https url, because we only use the CONNECT cmd for
// downloading https urls over a proxy i think
char *p = fullRequest;
if ( p && strncmp(p,"CONNECT ",8)==0 )
urlIsHttps = true;
// if going through a proxy do not use the ssl server, it will
// handle the encryption from itself to the host website. unfortunately
// then the http requests/responses are unencrypted from the
// proxy to us here.
if ( urlIsHttps && ! proxyIp ) {
if (!m_ssltcp.m_ready) {
// TODO: set an error here
log("https: Trying to get HTTPS site when SSL "
"TcpServer not ready: %s",url);
g_errno = ESSLNOTREADY;
return true;
}
tcp = &m_ssltcp;
}
int32_t pcLen = 0;
if ( postContent ) pcLen = gbstrlen(postContent);
char *req = NULL;
int32_t reqSize;
// if downloading an *httpS* url we have to send a
// CONNECT www.abc.com:443 HTTP/1.0\r\n\r\n request first
// and get back a connection established reply, before we can
// send the actual encrypted http stuff.
bool useHttpTunnel = ( proxyIp && urlIsHttps );
int32_t hostLen ;
int32_t port = defPort;
char *host = NULL;
if ( ! ip || useHttpTunnel )
host = getHostFast ( url , &hostLen , &port );
// this returns false and sets g_errno on error
if ( ! fullRequest ) {
if ( ! r.set ( url , offset , size , ifModifiedSince ,
userAgent , proto , doPost , cookie ,
// pass in proxyIp because if it is a
// request being sent to a proxy we have to
// say "GET http://www.xyz.com/" the full
// url, not just a relative path.
additionalHeader , pcLen , proxyIp ,
proxyUsernamePwdAuth ) ) {
log("http: http req error: %s",mstrerror(g_errno));
// TODO: ensure we close the socket on this error!
return true;
}
if ( g_conf.m_logDebugTcp )
log("archive: %s",r.m_reqBuf.getBufStart());
reqSize = r.getRequestLen();
int32_t need = reqSize + pcLen;
// if we are requesting an HTTPS url through a proxy then
// this will prepend a
// CONNECT www.abc.com:443 HTTP/1.0\r\n\r\n
// CONNECT www.gigablast.com:443 HTTP/1.0\r\n\r\n
// to the actual mime and we have to detect that
// below and just send that to the proxy. when the proxy
// sends back "HTTP/1.0 200 Connection established\r\n\r\n"
// we use ssl_write in tcpserver.cpp to send the original
// encrypted http request.
SafeBuf sb;
if ( useHttpTunnel ) {
sb.safePrintf("CONNECT ");
sb.safeMemcpy ( host, hostLen );
sb.safePrintf(":%"INT32" HTTP/1.0\r\n",port);
// sb.safePrintf("Host: ");
// sb.safeMemcpy ( host, hostLen );
// sb.safePrintf("\r\n");
// include proxy authentication info now
if ( proxyUsernamePwdAuth && proxyUsernamePwdAuth[0] ){
sb.safePrintf("Proxy-Authorization: Basic ");
sb.base64Encode(proxyUsernamePwdAuth,
gbstrlen(proxyUsernamePwdAuth)
);
sb.safePrintf("\r\n");
}
sb.safePrintf("\r\n");
sb.nullTerm();
need += sb.length();
}
req = (char *) mmalloc( need ,"HttpServer");
char *p = req;
if ( req && sb.length() ) {
gbmemcpy ( p , sb.getBufStart() , sb.length() );
p += sb.length();
}
if ( req ) {
gbmemcpy ( p , r.getRequest() , reqSize );
p += reqSize;
}
if ( req && pcLen ) {
gbmemcpy ( p , postContent , pcLen );
p += pcLen;
}
reqSize = p - req;
}
else {
// does not contain \0 i guess
reqSize = gbstrlen(fullRequest);
req = (char *) mdup ( fullRequest , reqSize,"HttpServer");
}
// . get the request from the static buffer and dup it
// . return true and set g_errno on error
if ( ! req ) return true;
// mdw23
//if ( g_conf.m_logDebugSpider )
// {
// SafeBuf tmp;
// tmp.safeMemcpy ( req , reqSize );
// tmp.nullTerm();
// log("spider: httprequest = %s", tmp.getBufStart() );
// }
// do we have an ip to send to? assume not
if ( proxyIp ) { ip = proxyIp ; port = proxyPort; }
// special NULL case
if ( !state || !callback ) {
// . send it away
// . callback will be called on completion of transaction
// . be sure to free "req/reqSize" in callback() somewhere
if ( ip )
return m_tcp.sendMsg ( ip ,
port ,
req ,
reqSize ,
reqSize ,
reqSize , // msgTotalSize
state ,
callback ,
timeout ,
maxTextDocLen ,
maxOtherDocLen );
// otherwise pass the hostname
return m_tcp.sendMsg ( host ,
hostLen ,
port ,
req ,
reqSize ,
reqSize ,
reqSize , // msgTotalSize
state ,
callback ,
timeout ,
maxTextDocLen ,
maxOtherDocLen );
}
// if too many downloads already, return error
//if ( respectDownloadLimit &&
// s_numOutgoingSockets >= g_conf.m_httpMaxDownloadSockets ||
if ( s_numOutgoingSockets >= MAX_DOWNLOADS ) {
mfree ( req, reqSize, "HttpServer" );
g_errno = ETOOMANYDOWNLOADS;
log("http: already have %"INT32" sockets downloading. Sending "
"back ETOOMANYDOWNLOADS.",(int32_t)MAX_DOWNLOADS);
return true;
}
// increment usage
PTRTYPE n = 0;
while ( states[n] ) {
n++;
// should not happen...
if ( n >= MAX_DOWNLOADS ) {
mfree ( req, reqSize, "HttpServer" );
g_errno = ETOOMANYDOWNLOADS;
log("http: already have %"INT32" sockets downloading",
(int32_t)MAX_DOWNLOADS);
return true;
}
}
states [n] = state;
callbacks[n] = callback;
s_numOutgoingSockets++;
// debug
log(LOG_DEBUG,"http: Getting doc with ip=%s state=%"PTRFMT" url=%s.",
iptoa(ip),(PTRTYPE)state,url);
// . send it away
// . callback will be called on completion of transaction
// . be sure to free "req/reqSize" in callback() somewhere
// . if using an http proxy, then ip should be valid here...
if ( ip ) {
if ( ! tcp->sendMsg ( ip ,
port ,
req ,
reqSize ,
reqSize ,
reqSize , // msgTotalSize
(void*)n ,
gotDocWrapper ,
timeout ,
maxTextDocLen ,
maxOtherDocLen ,
useHttpTunnel ) )
return false;
// otherwise we didn't block
states[n] = NULL;
callbacks[n] = NULL;
s_numOutgoingSockets--;
return true;
}
// otherwise pass the hostname
if ( ! tcp->sendMsg ( host ,
hostLen ,
port ,
req ,
reqSize ,
reqSize ,
reqSize , // msgTotalSize
(void*)n ,
gotDocWrapper ,
timeout ,
maxTextDocLen ,
maxOtherDocLen ) )
return false;
// otherwise we didn't block
states[n] = NULL;
callbacks[n] = NULL;
s_numOutgoingSockets--;
return true;
}
// . get a url's document
// . returns false if blocked, true otherwise
// . sets g_errno on error
// . IMPORTANT: we free doc/docLen, so NULLify s->m_readBuf if you want it
// . IMPORTANT: same goes for s->m_sendBuf
// . timeout in milliseconds since no read OR no write
// . proxyIp is 0 if we don't have one
bool HttpServer::getDoc ( int32_t ip,
int32_t port,
char *request,
int32_t requestLen,
void *state ,
void (* callback)( void *state , TcpSocket *s ) ,
int32_t timeout ,
int32_t maxTextDocLen ,
int32_t maxOtherDocLen ) {
//bool respectDownloadLimit ) {
TcpServer *tcp = &m_tcp;
//stupid incoming request has 1024 bytes mostly, while we need to
//send exactly what was needed
int32_t reqSize = gbstrlen ( request );
char *req = (char *) mdup ( request, reqSize,"HttpServer" );
if ( ! req ) return true;
// if too many downloads already, return error
if ( s_numOutgoingSockets >= MAX_DOWNLOADS ) {
mfree ( req, reqSize, "HttpServer" );
g_errno = ETOOMANYDOWNLOADS;
log("http: already have %"INT32" sockets downloading",
(int32_t)MAX_DOWNLOADS);
return true;
}
// increment usage
int32_t n = 0;
while ( states[n] ) {
n++;
// should not happen...
if ( n >= MAX_DOWNLOADS ) {
mfree ( req, reqSize, "HttpServer" );
g_errno = ETOOMANYDOWNLOADS;
log("http: already have %"INT32" sockets downloading",
(int32_t)MAX_DOWNLOADS);
return true;
}
}
states [n] = state;
callbacks[n] = callback;
s_numOutgoingSockets++;
// debug
log(LOG_DEBUG,"http: Getting doc with ip=%s state=%"PTRFMT". %s",
iptoa(ip),(PTRTYPE)state, req);
// . send it away
// . callback will be called on completion of transaction
// . be sure to free "req/reqSize" in callback() somewhere
// MDW: THIS IS RETURNING TRUE SOMEHOW w/o setting g_errno
if ( ! tcp->sendMsg ( ip ,
port ,
req ,
reqSize ,
reqSize ,
reqSize , // msgTotalSize
(void*)(PTRTYPE)n ,
gotDocWrapper ,
timeout ,
maxTextDocLen ,
maxOtherDocLen ) )
return false;
// otherwise we didn't block
states[n] = NULL;
callbacks[n] = NULL;
s_numOutgoingSockets--;
log("http: sendmsg returned true!: %s",mstrerror(g_errno));
return true;
}
void gotDocWrapper ( void *state, TcpSocket *s ) {
g_httpServer.gotDoc ( (int32_t)(PTRTYPE)state, s );
}
bool HttpServer::gotDoc ( int32_t n, TcpSocket *s ) {
void *state = states[n];
void (*callback)(void *state, TcpSocket *s) = callbacks[n];
// debug
log(LOG_DEBUG,"http: Got doc with state=%"PTRFMT".",(PTRTYPE)state);
states[n] = NULL;
callbacks[n] = NULL;
s_numOutgoingSockets--;
//figure out if it came back zipped, unzip if so.
//if(g_conf.m_gzipDownloads && !g_errno && s->m_readBuf)
// now wikipedia force gzip on us regardless
if( !g_errno && s->m_readBuf) {
// this could set g_errno to EBADMIME or ECORRUPTHTTPGZIP
s = unzipReply(s);
}
// callback
callback ( state, s );
return true;
}
// . handle an incoming HTTP request
void requestHandlerWrapper ( TcpSocket *s ) {
g_httpServer.requestHandler ( s );
}
// . a udp handler wrapper
// . the proxy sends us udp packets with msgtype = 0xfd ("forward")
void handleRequestfd ( UdpSlot *slot , int32_t niceness ) {
// if we are proxy, that is just wrong! a proxy does not send
// this msg to another proxy, only to the flock
// no! now a compression proxy will forward a query to a regular
// proxy so that the search result pages can be compressed to
// save bandwidth so we can serve APN's queries over lobonet
// which is only 2Mbps.
//if ( g_proxy.isCompressionProxy() ) { char *xx=NULL;*xx=0; }
if ( g_hostdb.m_myHost->m_type==HT_QCPROXY) {char *xx=NULL;*xx=0;}
// if niceness is 0, use the higher priority udpServer
//UdpServer *us = &g_udpServer;
// get the request
char *request = slot->m_readBuf;
int32_t requestSize = slot->m_readBufSize;
int32_t requestAlloc = slot->m_readBufMaxSize;
// sanity check, must at least contain \0 and ip (5 bytes total)
if ( requestSize < 5 ) { char *xx=NULL;*xx=0; }
// make a fake TcpSocket
TcpSocket *s = (TcpSocket *)mcalloc(sizeof(TcpSocket),"tcpudp");
// this sucks
if ( ! s ) {
log("http: could not allocate for TcpSocket. Out of memory.");
g_udpServer.sendErrorReply ( slot , g_errno );
return;
}
// HACK: Proxy.cpp crammed the real ip into the end of the request
s->m_ip = *(int32_t *)(request+requestSize-4);
// callee will free this buffer...
s->m_readBuf = request;
// actually remove the ending \0 as well as 4 byte ip
s->m_readOffset = requestSize - 5;
s->m_readBufSize = requestAlloc;
s->m_this = &g_httpServer.m_tcp;
// HACK: let TcpServer know to send a UDP reply, not a tcp reply!
s->m_udpSlot = slot;
// . let the TcpSocket free that readBuf when we free the TcpSocket,
// there in TcpServer.cpp::sendMsg()
// . PageDirectory.cpp actually realloc() the TcpSocket::m_readBuf
// so we have to be careful not to let UdpServer free it in the
// udpSlot because it will have been reallocated by PageDirectory.cpp
slot->m_readBuf = NULL;
// HACK: this is used as a unique identifier for registering callbacks
// so let's set the high bit here to avoid conflicting with normal
// TCP socket descriptors that might be reading the same file! But
// now we are not allowing proxy to forward regular file requests,
// so hopefully, we won't even use this hacked m_sd.
s->m_sd = 1234567;//(int32_t)slot | 0x80000000;
// if we are a proxy receiving a request from a compression proxy
// then use the proxy handler function
if ( g_proxy.isProxy() ) {
// this should call g_httpServer.sendDynamicPage() which
// should compress the 0xfd reply to be sent back to the
// compression proxy
g_proxy.handleRequest ( s );
return;
}
// log this out on gk144 to see why dropping
if ( g_conf.m_logDebugBuild )
log("fd: handling request transid=%"INT32" %s",
slot->m_transId, request );
// ultimately, Tcp::sendMsg() should be called which will free "s"
g_httpServer.requestHandler ( s );
}
// . if this returns false "s" will be destroyed
// . if request is not GET or HEAD we send an HTTP 400 error code
// . ALWAYS calls m_tcp.sendMsg ( s ,... )
// . may block on something before calling that however
// . NEVER calls m_tcp.destroySocket ( s )
// . One Exception: sendErrorReply() can call it if cannot form error reply
void HttpServer::requestHandler ( TcpSocket *s ) {
// debug msg
//log("got request, readBufUsed=%i",s->m_readOffset);
// parse the http request
HttpRequest r;
// debug
/*
unsigned char foo[1024];
unsigned char *pp = foo;
pp += sprintf ( (char *)pp,"GET /search?qcs=iso-8859-1&k0c=107207&code=1M9VNT6&spell=1&ns=2&nrt=0&rat=0&sc=1&DR=1&qh=0&bq2&q=");
//pp += sprintf ( (char *)pp,"GET /search?k0c=107207&code=1M9VNT6&spell=1&ns=2&nrt=0&rat=0&sc=1&DR=1&qh=0&bq2&q=");
static char ddd[] = {
0xc3, 0x83, 0xc6, 0x92, 0xc3, 0xa2, 0xe2, 0x80, 0x9e, 0xc2,
0xa2, 0xc3, 0x83, 0xc2, 0xa2, 0xc3, 0xa2, 0xe2, 0x80, 0x9a,
0xc2, 0xac, 0xc3, 0x82, 0xc2, 0xa6, 0xc3, 0x83, 0xc6, 0x92,
0xc3, 0xa2, 0xe2, 0x80, 0x9e, 0xc2, 0xa2, 0xc3, 0x83, 0xe2,
0x80, 0x9a, 0xc3, 0x82, 0xc2, 0x81, 0xc3, 0x83, 0xc6, 0x92,
0xc3, 0xa2, 0xe2, 0x80, 0x9e, 0xc2, 0xa2, 0xc3, 0x83, 0xc2,
0xa2, 0xc3, 0xa2, 0xe2, 0x80, 0x9a, 0xc2, 0xac, 0xc3, 0x82,
0xc2, 0xa1, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0xa2, 0xe2, 0x80,
0x9e, 0xc2, 0xa2, 0xc3, 0x83, 0xe2, 0x80, 0xb9, 0xc3, 0xa2,
0xe2, 0x82, 0xac, 0xc2, 0xa0, 0xc3, 0x83, 0xc6, 0x92, 0xc3,
0xa2, 0xe2, 0x80, 0x9e, 0xc2, 0xa2, 0xc3, 0x83, 0xc2, 0xa2,
0xc3, 0xa2, 0xe2, 0x80, 0x9a, 0xc2, 0xac, 0xc3, 0x82, 0xc2,
0xa6, 0x20, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0x8b, 0xc5, 0x93,
0xc3, 0x83, 0xe2, 0x80, 0x9a, 0xc3, 0x82, 0xc2, 0xa7, 0xc3,
0x83, 0xc6, 0x92, 0xc3, 0xa2, 0xe2, 0x80, 0x9e, 0xc2, 0xa2,
0xc3, 0x83, 0xc2, 0xa2, 0xc3, 0xa2, 0xe2, 0x80, 0x9a, 0xc2,
0xac, 0xc3, 0x85, 0xc2, 0xbe, 0xc3, 0x83, 0xc6, 0x92, 0xc3,
0xa2, 0xe2, 0x80, 0x9e, 0xc2, 0xa2, 0xc3, 0x83, 0xc2, 0xa2,
0xc3, 0xa2, 0xe2, 0x80, 0x9a, 0xc2, 0xac, 0xc3, 0x82, 0xc2,
0xa6, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0xa2, 0xe2, 0x80, 0x9e,
0xc2, 0xa2, 0xc3, 0x83, 0xc2, 0xa2, 0xc3, 0xa2, 0xe2, 0x80,
0x9a, 0xc2, 0xac, 0xc3, 0x82, 0xc2, 0xa0, 0xc3, 0x83, 0xc6,
0x92, 0xc3, 0x8b, 0xc5, 0x93, 0xc3, 0x83, 0xe2, 0x80, 0x9a,
0xc3, 0x82, 0xc2, 0xb8, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0xa2,
0xe2, 0x80, 0x9e, 0xc2, 0xa2, 0xc3, 0x83, 0xe2, 0x80, 0xb9,
0xc3, 0xa2, 0xe2, 0x82, 0xac, 0xc2, 0xa0, 0xc3, 0x83, 0xc6,
0x92, 0xc3, 0xa2, 0xe2, 0x80, 0x9e, 0xc2, 0xa2, 0xc3, 0x83,
0xc2, 0xa2, 0xc3, 0xa2, 0xe2, 0x80, 0x9a, 0xc2, 0xac, 0xc3,
0x82, 0xc2, 0xa6, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0x8b, 0xc5,
0x93, 0xc3, 0x83, 0xe2, 0x80, 0x9a, 0xc3, 0x82, 0xc2, 0xa9,
0x20, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0x8b, 0xc5, 0x93, 0xc3,
0x83, 0xe2, 0x80, 0x9a, 0xc3, 0x82, 0xc2, 0xa7, 0xc3, 0x83,
0xc6, 0x92, 0xc3, 0xa2, 0xe2, 0x80, 0x9e, 0xc2, 0xa2, 0xc3,
0x83, 0xc2, 0xa2, 0xc3, 0xa2, 0xe2, 0x80, 0x9a, 0xc2, 0xac,
0xc3, 0x85, 0xc2, 0xbe, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0x8b,
0xc5, 0x93, 0xc3, 0x83, 0xe2, 0x80, 0x9a, 0xc3, 0x82, 0xc2,
0xa8, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0xa2, 0xe2, 0x80, 0x9e,
0xc2, 0xa2, 0xc3, 0x83, 0xe2, 0x80, 0xa6, 0xc3, 0x82, 0xc2,
0xa0, 0xc3, 0x83, 0xc6, 0x92, 0xc3, 0x8b, 0xc5, 0x93, 0xc3,
0x83, 0xe2, 0x80, 0x9a, 0xc3, 0x82, 0xc2, 0xa6, 0xc3, 0x83,
0xc6, 0x92, 0xc3, 0xa2, 0xe2, 0x80, 0x9e, 0xc2, 0xa2, 0xc3,
0x83, 0xe2, 0x80, 0xa6, 0xc3, 0x82, 0xc2, 0xa0, 0xc3, 0x83,
0xc6, 0x92, 0xc3, 0x8b, 0xc5, 0x93, 0xc3, 0x83, 0xe2, 0x80,
0x9a, 0xc3, 0x82, 0xc2, 0xa9, 0x00, 0x00, 0xda, 0xda, 0xda,
0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda,
0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda,
0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0x74,
0x65, 0x73, 0x2c, 0x20, 0x68, 0x59, 0x00, 0x00, 0x00, 0xac,
0xed, 0x3b, 0x09, 0xac, 0xed, 0x3b, 0x09, 0x78, 0x51, 0xa7,
0x24, 0xf8, 0xd0, 0xa7, 0x24, 0x00, 0x00, 0x00, 0x00, 0x0a,
0x00};
for ( int32_t i = 0 ; i < 435 ; i++ ) {
// again:
*pp = ddd[i]; // rand() % 256;
//if ( *pp < 0x80 ) goto again;
pp++;
}
*pp = 0;
*/
// . since we own the data, we'll free readBuf on r's destruction
// . this returns false and sets g_errno on error
// . but it should still set m_request to the readBuf to delete it
// so don't worry about memory leaking s's readBuf
// . if the request is bad then return an HTTP error code
// . this should copy the request into it's own local buffer
// . we now pass "s" so we can get the src ip/port to see if
// it's from lenny
bool status = r.set ( s->m_readBuf , s->m_readOffset , s ) ;
//bool status = r.set ( (char *)foo , pp - foo , s ) ;
// is this the admin
//bool isAdmin = g_collectiondb.isAdmin ( &r , s );
// i guess assume MASTER admin...
//bool isAdmin = g_users.hasPermission ( &r , PAGE_MASTER , s );
bool isAdmin = r.isLocal();
// never proxy admin pages for security reasons
if ( s->m_udpSlot ) isAdmin = false;
//bool isIpInNetwork = g_hostdb.isIpInNetwork ( s->m_ip );
// . if host does not allow http requests (except for admin) then bail
// . used to prevent seo/email spammers from querying other machines
// and getting around our seo robot protection
//if ( ! g_conf.m_httpServerEnabled ) {
//&& ! isAdmin &&
// quick hack so we can add ips to the connect ips list in
// the master controls security table
// ! g_conf.isConnectIp ( s->m_ip ) ) {
// log("query: Returning 403 Forbidden. HttpServer is disabled "
// "in the master controls. ip=%s",iptoa(s->m_ip));
// sendErrorReply ( s , 403 , "Forbidden" );
// return;
//}
// get the server this socket uses
TcpServer *tcp = s->m_this;
// get the max sockets that can be opened at any one time
int32_t max;
if ( tcp == &m_ssltcp ) max = g_conf.m_httpsMaxSockets;
else max = g_conf.m_httpMaxSockets;
// just a safety catch
if ( max < 2 ) max = 2;
// limit injects to less sockets than the max, so the administrator
// and regular queries will take precedence
int32_t imax = max - 10;
if ( imax < 10 ) imax = max - 1;
if ( imax < 2 ) imax = 2;
if ( strncmp ( s->m_readBuf , "GET /inject" , 11 ) == 0 ) {
// reset "max" to something smaller
max = imax;
// do not consider injects to be coming from admin ever
isAdmin = false;
}
// enforce open connections here
//if ( used >= g_conf.m_httpMaxSockets + 10 ) {
// log("query: Too many sockets open for ip=%s. Destroying.",
// iptoa(s->m_ip));
// m_tcp.destroySocket ( s );
// return;
//}
// enforce the open socket quota iff not admin and not from intranet
if ( ! isAdmin && tcp->m_numIncomingUsed >= max &&
// make sure request is not from proxy
! s->m_udpSlot &&
!tcp->closeLeastUsed()) {
static int32_t s_last = 0;
static int32_t s_count = 0;
int32_t now = getTimeLocal();
if ( now - s_last < 5 )
s_count++;
else {
log("query: Too many sockets open. Sending 500 "
"http status code to %s. (msgslogged=%"INT32")",
iptoa(s->m_ip),s_count);
s_count = 0;
s_last = now;
}
sendErrorReply ( s , 500 , "Too many sockets open.");
// count as a failed query so we send an email alert if too
// many of these happen
g_stats.m_closedSockets++;
return;
}
// . read Buf should be freed on s's recycling/destruction in TcpServer
// . always free the readBuf since TcpServer does not
// . be sure not to set s->m_readBuf to NULL because it's used by
// TcpServer to determine if we're sending/reading a request/reply
// mfree ( s->m_readBuf , s->m_readBufSize );
// set status to false if it's not a HEAD or GET request
//if ( ! r.isGETRequest() && ! r.isHEADRequest() ) status = false;
// if the HttpRequest was bogus come here
if ( ! status ) {
// log a bad request
log("http: Got bad request from %s: %s",
iptoa(s->m_ip),mstrerror(g_errno));
// cancel the g_errno, we'll send a BAD REQUEST reply to them
g_errno = 0;
// . this returns false if blocked, true otherwise
// . this sets g_errno on error
// . this will destroy(s) if cannot malloc send buffer
sendErrorReply ( s , 400, "Bad Request" );
return;
}
// ok, we got an authenticated proxy request
if ( r.m_isSquidProxyRequest ) {
processSquidProxyRequest ( s , &r );
return;
}
// log the request iff filename does not end in .gif .jpg .
char *f = r.getFilename();
int32_t flen = r.getFilenameLen();
bool isGif = ( f && flen >= 4 && strncmp(&f[flen-4],".gif",4) == 0 );
bool isJpg = ( f && flen >= 4 && strncmp(&f[flen-4],".jpg",4) == 0 );
bool isBmp = ( f && flen >= 4 && strncmp(&f[flen-4],".bmp",4) == 0 );
bool isPng = ( f && flen >= 4 && strncmp(&f[flen-4],".png",4) == 0 );
bool isIco = ( f && flen >= 4 && strncmp(&f[flen-4],".ico",4) == 0 );
bool isPic = (isGif | isJpg | isBmp | isPng || isIco);
// get time format: 7/23/1971 10:45:32
// . crap this cores if we use getTimeGlobal() and we are not synced
// with host #0, so just use local time i guess in that case
time_t tt ;
if ( isClockInSync() ) tt = getTimeGlobal();
else tt = getTimeLocal();
struct tm *timeStruct = localtime ( &tt );
char buf[64];
strftime ( buf , 100 , "%b %d %T", timeStruct);
// save ip in case "s" gets destroyed
int32_t ip = s->m_ip;
// . likewise, set cgi buf up here, too
// . if it is a post request, log the posted data, too
/*
char cgi[20058];
cgi[0] = '\0';
if ( r.isPOSTRequest() ) {
int32_t plen = r.m_cgiBufLen;
if ( plen >= 20052 ) plen = 20052;
char *pp1 = cgi ;
char *pp2 = r.m_cgiBuf;
// . when parsing cgi parms, HttpRequest converts the
// &'s to \0's so it can avoid having to malloc a
// separate m_cgiBuf
// . now it also converts ='s to 0's, so flip flop back
// and forth
char dd = '=';
for ( int32_t i = 0 ; i < plen ; i++ , pp1++, pp2++ ) {
if ( *pp2 == '\0' ) {
*pp1 = dd;
if ( dd == '=' ) dd = '&';
else dd = '=';
continue;
}
if ( *pp2 == ' ' ) *pp1 = '+';
else *pp1 = *pp2;
}
if ( r.m_cgiBufLen >= 20052 ) {
pp1[0]='.'; pp1[1]='.'; pp1[2]='.'; pp1 += 3; }
*pp1 = '\0';
}
*/
//get this value before we send the reply, because r can be
//destroyed when we send.
int32_t dontLog = r.getLong("dontlog",0);
// turn off for now
//dontLog = 0;
// !!!!
// TcpServer::sendMsg() may free s->m_readBuf if doing udp forwarding
// !!!!
char stackMem[1024];
int32_t maxLen = s->m_readOffset;
if ( maxLen > 1020 ) maxLen = 1020;
gbmemcpy(stackMem,s->m_readBuf,maxLen);
stackMem[maxLen] = '\0';
// . sendReply returns false if blocked, true otherwise
// . sets g_errno on error
// . this calls sendErrorReply (404) if file does not exist
// . g_msg is a ptr to a message like " (perm denied)" for ex. and
// it should be set by PageAddUrl.cpp, PageResults.cpp, etc.
g_msg = "";
sendReply ( s , &r , isAdmin) ;
// log the request down here now so we can include
// "(permission denied)" on the line if we should
if ( ! isPic ) {
// what url refered user to this one?
char *ref = r.getReferer();
// skip over http:// in the referer
if ( strncasecmp ( ref , "http://" , 7 ) == 0 ) ref += 7;
// fix cookie for logging
/*
char cbuf[5000];
char *p = r.m_cookiePtr;
int32_t plen = r.m_cookieLen;
if ( plen >= 4998 ) plen = 4998;
char *pend = r.m_cookiePtr + plen;
char *dst = cbuf;
for ( ; p < pend ; p++ ) {
*dst = *p;
if ( ! *p ) *dst = ';';
dst++;
}
*dst = '\0';
*/
// store the page access request in accessdb
//g_accessdb.addAccess ( &r , ip );
// if autobanned and we should not log, return now
if ( g_msg && ! g_conf.m_logAutobannedQueries &&
strstr(g_msg,"autoban") ) {
}
else if(isAdmin && dontLog) {
//dont log if they ask us not to.
}
// . log the request
// . electric fence (efence) seg faults here on iptoa() for
// some strange reason
else if ( g_conf.m_logHttpRequests ) // && ! cgi[0] )
logf (LOG_INFO,"http: %s %s %s %s "
//"cookie=\"%s\" "
//"%s "
"%s",
buf,iptoa(ip),
// can't use s->m_readBuf[] here because
// might have called TcpServer::sendMsg() which
// might have freed it if doing udp forwarding.
// can't use r.getRequest() because it inserts
// \0's in there for cgi parm parsing.
stackMem,
//s->m_readBuf,//r.getRequest(),
ref,
//r.m_cookiePtr,
//r.getUserAgent(),
g_msg);
/*
else if ( g_conf.m_logHttpRequests )
logf (LOG_INFO,"http: %s %s %s %s %s "
//"cookie=\"%s\" "
//"%s "
"%s",
buf,iptoa(ip),
s->m_readBuf,//r.getRequest(),
cgi,
ref,
//cbuf,//r.m_cookiePtr,
//r.getUserAgent(),
g_msg);
*/
}
// if no error, we completed w/o blocking so return
//if ( ! g_errno ) return;
// if g_errno was set then send an error msg
//return sendErrorReply ( s, 500 , mstrerror(g_errno) );
}
/*
// it's better to hardcode this so we never lose it!
bool sendPageRobotsTxt ( TcpSocket *s , HttpRequest *r ) {
SafeBuf sb;
sb.safePrintf ( "User-Agent: *\n"
"Disallow: *\n"
//"Disallow: /search?makewidget=1\n"
//"Disallow: /search?clockset=\n"
"\n"
);
// this should copy it since sb is on stack
return g_httpServer.sendDynamicPage ( s ,
sb.getBufStart(),
sb.m_length ,
0 ,
"text/html");
}
*/
bool endsWith(char *haystack, int haystackLen, char *needle, int needleLen) {
return haystackLen >= needleLen && !strncmp(haystack + haystackLen - needleLen, needle, needleLen);
}
#include "Pages.h" // sendPageAPI, printApiForPage()
// . reply to a GET (including partial get) or HEAD request
// . HEAD just returns the MIME header for the file requested
// . returns false if blocked, true otherwise
// . sets g_errno on error
// . it calls TcpServer::sendMsg(s,...)
// . with a File * as the callback data
// . and with cleanUp() as the callback function
// . if sendMsg(s,...) blocks this cleanUp() will be called before the
// socket gets recycled or destroyed (on error)
bool HttpServer::sendReply ( TcpSocket *s , HttpRequest *r , bool isAdmin) {
// get the server this socket uses
TcpServer *tcp = s->m_this;
// if there is a redir=http:// blah in the request then redirect
int32_t redirLen = r->getRedirLen() ;
char *redir = NULL;
// . we may be serving multiple hostnames
// . www.gigablast.com, gigablast.com, www.inifinte.info,
// infinite.info, www.microdemocracy.com
// . get the host: field from the MIME
// . should be NULL terminated
char *h = r->getHost();
if(redirLen > 0) redir = r->getRedir();
else if (!isAdmin &&
*g_conf.m_redirect != '\0' &&
// was "raw"
r->getLong("xml", -1) == -1 &&
// do not redirect a 'gb proxy stop' request away,
// which POSTS cast=0&save=1. that is done from the
// command line, and for some reason it is not isAdmin
r->getLong("save", -1) != -1 &&
r->getString("site") == NULL &&
r->getString("sites") == NULL) {
//direct all non-raw, non admin traffic away.
redir = g_conf.m_redirect;
redirLen = gbstrlen(g_conf.m_redirect);
}
char *hdom = h;
if ( strncasecmp(hdom,"www.",4) == 0 ) hdom += 4;
// auto redirect eventguru.com to www.eventguru.com so cookies
// are consistent
if ( ! redir &&
( strcasecmp ( h , "eventguru.com" ) == 0 ||
strcasecmp ( hdom , "flurbit.com" ) == 0 ||
strcasecmp ( hdom , "flurbits.com" ) == 0 ||
strcasecmp ( hdom , "flurpit.com" ) == 0 ||
strcasecmp ( hdom , "flurbot.com" ) == 0 ||
strcasecmp ( hdom , "flurbits.com" ) == 0 ||
strcasecmp ( hdom , "flurbyte.com" ) == 0 ||
strcasecmp ( hdom , "eventstereo.com" ) == 0 ||
strcasecmp ( hdom , "eventcrier.com" ) == 0 ||
strcasecmp ( hdom , "eventwidget.com" ) == 0 ) ) {
redir = "http://www.eventguru.com/";
redirLen = gbstrlen(redir);