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