1
2 /***************************************************************************
3 * mghttpants.cpp
4 *
5 * Wed Sep 6 22:19:52 2006
6 * Copyright 2006 liubin,China
7 * Email multiget@gmail.com
8 ****************************************************************************/
9
10 /*
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25 /*
26 the UTF-8 Chinese char will break vc6 compile
27
28 this file is created on 2006/09/04 by liubin,China
29
30
31 */
32
33 #ifdef WIN32
34 #include <winsock2.h>
35 #endif
36 #include "mgapp.h"
37 #include "mghttpants.h"
38 #include "mgfilemanager.h"
39 #include "mgsingletask.h"
40 #include "mgurlparser.h"
41 #ifdef WIN32
42 #include <windows.h>
43 #endif
44 #include <pthread.h>
45
46 using namespace std;
47
48 #define _MGSTR(s) wxGetApp().GetStr(s)
49
CMgHttpAnts(CMgSingleTask * parent,CMgFileManager * fm,std::string url,int antid,int retry,int retrywait,llong from,llong tsize,std::string refer)50 CMgHttpAnts::CMgHttpAnts(
51 CMgSingleTask *parent,
52 CMgFileManager *fm,
53 std::string url,
54 int antid, //1 based
55 int retry,
56 int retrywait,
57 llong from,
58 llong tsize,
59 std::string refer
60 )
61 {
62 m_pParent = parent;
63 m_pFM = fm;
64
65 m_nAntId = antid;
66 m_nRetry = retry;
67 m_nRetryWait = retrywait;
68 m_nFrom = from;
69 m_nFileSize = tsize;
70
71 //get refer,host,file from url
72 CUrlParser par;
73 par.SetUrl( url );
74 m_sUrl = par.GetRawUrl();
75 m_file = par.GetEscFilePathName();
76 m_host = par.GetServer();
77 m_sServer = par.GetServer();
78 m_Port = par.GetPort();
79 m_refer = refer.empty() ? par.GetRefer() : refer;
80 m_nTotalByte = 0;
81 }
82
~CMgHttpAnts()83 CMgHttpAnts::~CMgHttpAnts()
84 {
85 }
86
87
88
OutMsg(string str,_MSGTYPE type)89 void CMgHttpAnts::OutMsg( string str, _MSGTYPE type )
90 {
91 m_pParent->OutMsg( m_nAntId, str, type );
92 }
93
94
95 //return value
96 // <0 : something wrong ,task fail
97 // =0 : redirect to new url
98 // >0 : finish piece
Go()99 int CMgHttpAnts::Go()
100 {
101
102 int nret;
103
104 //int oldstate;
105
106 again:
107 //make connection
108 OutMsg( _MGSTR ( _S_ANTS_CONNECTING ) + m_sServer + string( "..." ) );
109
110 if ( !Connect( m_sServer.c_str(), m_Port ) )
111 {
112 OutMsg( _MGSTR ( _S_ANTS_CONNECTFAIL ), MSG_WARNNING );
113
114 if ( Retry() )
115 {
116 goto again;
117 }
118 else
119 {
120 OutMsg( _MGSTR ( _S_ANTS_NORETRY ), MSG_ERROR );
121 return -1;
122 }
123
124 }
125
126
127 //remove http header info we don't want
128 if ( !GetFile( m_file.c_str(), m_nFrom + m_nTotalByte, m_refer.c_str() ) )
129 {
130 OutMsg( _MGSTR ( _S_ANTS_FAILTOGETFILE ), MSG_WARNNING );
131
132 if ( Retry() )
133 {
134 goto again;
135 }
136 else
137 {
138 OutMsg( _MGSTR ( _S_ANTS_NORETRY ), MSG_ERROR );
139 return -2;
140 }
141 }
142
143
144 char buf[ 100 ];
145 sprintf( buf, (_MGSTR ( _S_ANTS_RECVFILEDATA )).c_str(), m_nFrom + m_nTotalByte );
146 OutMsg( buf, MSG_INFO );
147
148 llong ndata = 0;
149
150 nret = GetData( m_nFrom + m_nTotalByte, ndata );
151
152 if ( nret == 0 )
153 { //ok
154
155 OutMsg( _MGSTR ( _S_ANTS_FINISHNORMAL ) , MSG_SUCCESS );
156 return 1;
157
158 }
159 else
160 { //error
161
162 switch ( nret )
163 {
164
165 case -1:
166 OutMsg( _MGSTR ( _S_ANTS_WRITEERROR ), MSG_WARNNING );
167 break;
168
169 case - 2:
170 OutMsg( _MGSTR ( _S_ANTS_NETERROR ), MSG_WARNNING );
171 break;
172
173 case - 3:
174 OutMsg( _MGSTR ( _S_ANTS_CHANGEURL ), MSG_WARNNING );
175 break;
176
177 default:
178 OutMsg( "Other error", MSG_WARNNING );
179 break;
180 }
181
182
183 m_nTotalByte += ndata;
184
185 if ( nret == -3 )
186 {
187 //goto again;
188 return -3;
189 }
190 else if ( Retry() )
191 {
192 goto again;
193
194 }
195 else
196 {
197 OutMsg( _MGSTR ( _S_ANTS_NORETRY ), MSG_ERROR );
198 return nret;
199 }
200 }
201 }
202
203
204 //发送请求文件命令
GetFile(const char * filename,llong pos,const char * refer)205 bool CMgHttpAnts::GetFile( const char* filename, llong pos, const char* refer )
206 {
207
208 if ( SendHttpGetRequest( m_host.c_str(), filename, pos, refer ) )
209 {
210 return GetHead();
211 }
212
213 return false;
214
215 }
216
217 //获取数据
GetData(llong spos,llong & bytes)218 int CMgHttpAnts::GetData( llong spos, llong& bytes )
219 {
220
221 int movepos = 0;
222 int nret;
223 llong total = 0; //本次已经接收的数据,最后返回给bytes
224 unsigned char buffer[ RECVBUF ];
225
226 while ( 1 )
227 {
228 nret = Read( buffer + movepos, RECVBUF - movepos );
229
230 if ( nret < 0 )
231 {
232 //OutMsg( "network error while read data.", MSG_WARNNING );
233 //if buffer have old data, write out
234 /*/
235 bytes=total;
236 return -2;
237 /*/
238
239 if ( movepos > 0 )
240 {
241
242 int wret = WriteData( spos + total, movepos, buffer );
243
244 if ( wret < 0 && wret != -3 )
245 { //write file error
246 bytes = total;
247 return -1;
248 }
249 else if ( wret < 0 && wret == -3 )
250 {
251 bytes = total;
252 return -3;
253 }
254 else if ( wret == 0 )
255 { //write file ok
256 bytes = total + movepos;
257 return 0;
258 }
259 else
260 { //data not end ,net fail
261 bytes = total + movepos;
262 return -2;
263 }
264 }
265 else
266 {
267 bytes = total;
268 return -2;
269 }
270
271 //*/
272 }
273 else if ( nret == 0 )
274 {
275 int wret = WriteData( spos + total, movepos, buffer, true );
276
277 if ( wret < 0 && wret != -3 )
278 {
279 bytes = total;
280 return -1;
281 }
282 else if ( wret < 0 && wret == -3 )
283 {
284 bytes = total;
285 return -3;
286 }
287 else if ( wret == 0 )
288 {
289 bytes = total + movepos;
290 return 0;
291 }
292 else
293 { //wret > 0
294 //OutMsg( "file length doubt!!", MSG_WARNNING );
295 bytes = total + movepos;
296 return 0;
297 }
298
299 }
300 else //nret>0 网络接收正常
301 {
302 movepos += nret;
303
304 if ( movepos >= RECVBUF - 1024 )
305 {
306 //buffer full , write outCMgFtpAnts
307 int wret = WriteData( spos + total, movepos, buffer );
308
309 if ( wret < 0 && wret != -3 )
310 {
311 bytes = total;
312
313 return -1; //写数据错
314 }
315 else if ( wret < 0 && wret == -3 )
316 {
317 bytes = total;
318 return -3;
319 }
320 else if ( wret == 0 )
321 {
322 total += movepos;
323 movepos = 0;
324 bytes = total;
325
326 return 0;
327 }
328 else
329 {
330
331 total += movepos;
332 movepos = 0;
333
334 continue;
335 }
336 }
337 else
338 {
339 continue;
340 }
341 } //if
342 } //while(1)
343
344 return 0;
345 }
346
WriteData(llong offset,int len,unsigned char * buf,bool end)347 int CMgHttpAnts::WriteData( llong offset, int len, unsigned char *buf, bool end )
348 {
349
350 int OldState, nret, us;
351 pthread_setcancelstate ( PTHREAD_CANCEL_DISABLE, &OldState );
352
353 nret = m_pFM->FileData( m_nAntId , offset, len, buf, end, us );
354
355 pthread_setcancelstate ( OldState, NULL );
356
357 if ( us > 0 )
358 #ifdef WIN32
359 Sleep(1000*us);
360 #else
361 usleep( us );
362 #endif
363 return nret;
364
365 }
366
367
GetHead()368 bool CMgHttpAnts::GetHead()
369 {
370
371 char buf[ 1024 ];
372 int pos = 0;
373 int nret;
374
375 if ( ( nret = Read( buf + pos, 4 ) ) <= 0 )
376 {
377 return false; //先收4个字节
378 }
379
380 pos += nret;
381
382 while ( !( buf[ pos - 1 ] == '\n' && buf[ pos - 2 ] == '\r' &&
383 buf[ pos - 3 ] == '\n' && buf[ pos - 4 ] == '\r' ) && pos < 1022 )
384 {
385 if ( ( nret = Read( buf + pos, 1 ) ) <= 0 )
386 {
387 return false;
388 }
389 else
390 {
391 pos += nret;
392 }
393 }
394
395 if ( pos >= 1022 )
396 return false;
397
398
399 buf[ pos ] = 0;
400
401 int movepos = 0;
402
403 char line[ 256 ];
404
405 int linebyte;
406
407 int nRetCode = -1;
408
409 while ( ( linebyte = GetBufLine( buf + movepos, pos, line ) ) > 0 )
410 {
411 movepos += linebyte;
412
413 if ( strlen( line ) > 0 )
414 OutMsg( line, MSG_IN );
415
416
417
418 if ( strncasecmp( line, "HTTP/1.", 7 ) == 0 )
419 {
420
421 char retcode[ 4 ];
422 memcpy( retcode, line + 9, 3 );
423 retcode[ 3 ] = 0;
424 nRetCode = atoi( retcode );
425 }
426 }
427
428
429 if ( nRetCode / 100 != 2 )
430 {
431 char buf[ 20 ];
432 sprintf( buf, "retcode=%d,fail", nRetCode );
433
434 OutMsg( buf, MSG_ERROR );
435
436 return false;
437 }
438
439 return true;
440 }
441
Retry()442 bool CMgHttpAnts::Retry()
443 {
444 if ( --m_nRetry > 0 )
445 {
446 char buf[ 50 ];
447
448 sprintf( buf, (_MGSTR ( _S_ANTS_WAITTORETRY )).c_str(), m_nRetryWait );
449
450 OutMsg( buf );
451
452 m_pParent->m_nError++;
453 #ifdef WIN32
454 Sleep( 1000*m_nRetryWait );
455 #else
456 sleep( m_nRetryWait );
457 #endif
458 return true;
459 }
460
461 return false;
462 }
463
464 /*
465 void CMgHttpAnts::AnalysisHeader(
466 char buf, //IN buf have header content ended with 0
467 std::string prestr, //IN
468 bool& redirect, //OUT
469 std::string& redirection, //OUT
470 llong& filesize, //OUT
471 int& retcode //OUT
472 )
473 {
474
475 filesize=-1;
476 retcode=-1;
477 redirect=false;
478
479 int movepos = 0;
480 char line[ 200 ]; //a line don't longer than 200
481 int linebyte; //line length
482
483 // m_RetCode = -1;
484 // m_nFileSize=-1;
485
486 while ( ( linebyte = GetBufLine( buf + movepos, headpos, line ) ) > 0 )
487 {
488 if ( strlen( line ) > 0 ) { OutMsg( line, 2 );}
489
490 movepos += linebyte;
491
492 #ifdef WIN32
493 if ( strnicmp(line,"HTTP/1.", 7 ) == 0 )
494 #else
495 if ( strncasecmp( line, "HTTP/1.", 7 ) == 0 )
496 #endif
497 {
498
499 char tempcode[ 4 ];
500 memcpy( tempcode, line + 9, 3 );
501 tempcode[ 3 ] = 0;
502 retcode = atoi( tempcode );
503
504 }
505 #ifdef WIN32
506 else if(strnicmp( line, "CONTENT-LENGTH:", 15 ) == 0 )
507 #else
508 else if ( strncasecmp( line, "CONTENT-LENGTH:", 15 ) == 0 )
509 #endif
510 {
511
512 char slen[ 24 ] = {0};
513 strcpy( slen, line + 15 );
514 sscanf( slen, "%lld", &filesize );
515
516 }
517 #ifdef WIN32
518 else if( strnicmp( line, "LOCATION:", 9 ) == 0 )
519 #else
520 else if ( strncasecmp( line, "LOCATION:", 9 ) == 0 )
521 #endif
522 {
523 //some time not begin with http:// or ftp://
524 char redirect[ 512 ] = {0};
525 memcpy( redirect, line + 9, strlen( line ) - 9 );
526 redirection = std::string( redirect );
527 Trim(redirection);
528 redirect = true;
529 #ifdef WIN32
530 if( strnicmp( m_Redirection.c_str(), "HTTP://", 7 )!=0 &&
531 strnicmp( m_Redirection.c_str(), "FTP://", 6)!=0)
532 #else
533 if( strncasecmp( m_Redirection.c_str(), "HTTP://", 7 )!=0 &&
534 strncasecmp( m_Redirection.c_str(), "FTP://", 6)!=0)
535 #endif
536 {
537 //not a full url,append something to head
538 redirection=std::string("http://")+ m_server + prestr +
539 std::string("/") + redirection;
540 }
541
542 }
543 #ifdef WIN32
544 else if(strnicmp( line, "SET-COOKIE:", 11 ) == 0 )
545 #else
546 else if ( strncasecmp( line, "SET-COOKIE:", 11 ) == 0 )
547 #endif
548 {
549 char cookie[ 512 ] = {0};
550
551 int emp=0,end;
552 while ( line[ emp + 11 ] == ' ' )
553 emp++;
554
555 end=emp;
556 while ( line[ end + 11 ] != ';' && line[ end ] )
557 end++;
558
559 memcpy( cookie, line + 11 + emp, end - emp );
560 cookie [ end - emp ]=0;
561
562 AddCookie( std::string( cookie ) );
563
564 }
565 }
566 }
567
568 //trim space at head and rear
569 void CMgHttpAnts::Trim(std::string& str)
570 {
571 string::size_type pos = str.find_last_not_of(' ');
572 if(pos != string::npos) {
573 str.erase(pos + 1);
574 pos = str.find_first_not_of(' ');
575 if(pos != string::npos) str.erase(0, pos);
576 }
577 else str.erase(str.begin(), str.end());
578 }
579 */
580
581