📄 http.cpp
字号:
/*
assniffer - http.cpp (HTTP connection analysis)
Copyright (C) 2004 Cockos Incorporated
assniffer is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
assniffer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with assniffer; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "platform.h"
#include "pcap.h"
#include "http.h"
// configurable items of http.cpp
int g_config_usemime=2; // 1=append, 2=replace extension
int g_config_debugfn=0;
int g_config_subdirs=1;
char *g_config_leadpath=NULL;
// some utility functions
#ifdef _WIN32
char *skip_root(char *path)
{
char *p = CharNext(path);
char *p2 = CharNext(p);
if (*path && *p == ':' && *p2=='\\')
{
return CharNext(p2);
}
else if (*path == '\\' && *p == '\\')
{
// skip host and share name
int x = 2;
while (x--)
{
while (!IS_DIR_CHAR(*p2))
{
if (!*p2)
return NULL;
p2 = CharNext(p2);
}
p2 = CharNext(p2);
}
return p2;
}
else
return NULL;
}
#endif
void url_decode(char *in, char *out, int maxlen)
{
while (*in && maxlen>1)
{
if (*in == '+')
{
in++;
*out++=' ';
}
else if (*in == '%' && in[1] != '%' && in[1])
{
int a=0;
int b=0;
for ( b = 0; b < 2; b ++)
{
int r=in[1+b];
if (r>='0'&&r<='9') r-='0';
else if (r>='a'&&r<='z') r-='a'-10;
else if (r>='A'&&r<='Z') r-='A'-10;
else break;
a*=16;
a+=r;
}
if (b < 2) *out++=*in++;
else { *out++=a; in += 3;}
}
else *out++=*in++;
maxlen--;
}
*out=0;
}
HTTP_context::HTTP_context(int concnt)
{
m_mime_subtype[0]=0;
m_concnt=concnt;
m_fail=0;
m_bytes_timeout_scanget = 256;
m_bytes_timeout_scanreply = 256;
m_http_reply_code=0;
m_hasfoundget=0;
m_done=0;
m_fp=0;
m_fn[0]=0;
strcpy(m_host,"unknown");
m_hasfoundhttpreply=0;
m_is_gz=0;
m_ischunked=0;
m_chunkpos=0;
m_content_length=-1;
m_content_length_orig=-1;
}
HTTP_context::~HTTP_context()
{
if (m_fp)
{
fclose(m_fp);
if (m_is_gz)
{
char buf[8192];
sprintf(buf,"gzip -df \"%s\"",finalfn);
system(buf);
}
}
}
// returns bytes used
int HTTP_context::onRequestStream(unsigned char *payload, int payload_len)
{
if (m_hasfoundget) return 0; // if we've already parsed a get, we're done
int startpos;
for (startpos = 0; startpos <= payload_len-4; startpos++)
{
if (!memcmp(payload+startpos,"GET ",4)) break;
}
m_bytes_timeout_scanget -= startpos;
if (m_bytes_timeout_scanget < 0)
{
m_fail=1;
return 0;
}
if (startpos > payload_len-4)
{
return startpos;
}
int endptr=startpos;
while (endptr <= payload_len-4)
{
if (!memcmp(payload+endptr,"\r\n\r\n",4))
{
m_hasfoundget++;
break;
}
endptr++;
}
if (!m_hasfoundget)
{
return startpos; // wait for full request
}
endptr+=4;
// startpos is start of get block, endptr is end, both offsets
int l=startpos+4;
int haddot=0;
while (l < endptr && payload[l] != '\n' && payload[l] != '\r' && payload[l] != ' ' && payload[l])
{
l++;
}
char buf[512];
{
char obuf[512];
lstrcpyn(obuf,(char*)payload+startpos+4,min(l-startpos-4+1,sizeof(obuf)));
// urldecode obuf to buf
url_decode(obuf,buf,sizeof(buf)-1);
}
printf("get_request:%s\n",buf);
{
char *p=buf;
int allowslashes=!!g_config_subdirs;
while (*p)
{
if (*p == '?' || *p == '&' || *p == ';' || *p == '=')
{
allowslashes=0;
}
if (*p == '/' || *p == '\\')
{
if (allowslashes) *p='/';
else *p='_';
}
else if (*p == '?' || *p == '*' || *p == '|' || *p == ':')
*p = '_';
p++;
}
p=buf;
while (*p == ' ') p++;
if (!*p || !p[1])
{
strcpy(m_fn,"_index.html");
if (g_config_subdirs) m_fn[0] = '/';
}
else lstrcpyn(m_fn,p,256);
}
int x;
for (x = startpos+4; x < endptr-4; x ++)
{
if (!strnicmp((char*)payload+x,"\nHost:",6))
{
x+=6;
while (payload[x] == ' ' && x < endptr) x++;
int sx=x;
while (payload[x] != '\r' && payload[x] != '\n' && x < endptr) x++;
if (!strnicmp((char*)payload+sx,"www.",4)) sx+=4;
lstrcpyn(m_host,(char*)payload+sx,min(x-sx+1,sizeof(m_host)));
{
char *p=m_host;
while (*p)
{
if (*p == '/' || *p == '\\' || *p == '?' || *p == '*' || *p == '|' || *p == ':')
{
*p='_';
}
p++;
}
}
//printf("host:|%s|\n",m_host);
}
}
return endptr;
}
int HTTP_context::isDone() { return m_done; }
// returns amount used, if any
int HTTP_context::onReplyData(unsigned char *payload, int payload_len)
{
if (!m_hasfoundget || m_done) return 0;
unsigned char *payload_orig=payload;
if (!m_hasfoundhttpreply)
{
int hdrstart;
for (hdrstart = 0; hdrstart <= payload_len-4; hdrstart++)
{
if (!memcmp(payload+hdrstart,"HTTP",4)) break;
}
m_bytes_timeout_scanreply -= hdrstart;
if (m_bytes_timeout_scanreply < 0)
{
m_fail=1;
return 0;
}
if (hdrstart > payload_len-4)
{
return hdrstart; // no header
}
int hdrend;
for (hdrend = hdrstart; hdrend <= payload_len-4; hdrend ++)
{
if (!memcmp(payload+hdrend,"\r\n\r\n",4)) break;
}
if (hdrend > payload_len-4)
{
return hdrstart; // no end yet
}
hdrend+=4;
m_hasfoundhttpreply=1;
//printf("got HTTP reply\n");
int x;
for (x = hdrstart; x < hdrend-4; x ++)
{
if (payload[x] == '\r' || payload[x] == '\n') break;
}
{
char tmp[512];
lstrcpyn(tmp,(char*)payload+hdrstart,min(x-hdrstart+1,sizeof(tmp)));
char *p=tmp;
while (*p != ' ' && *p) p++;
while (*p == ' ') p++;
m_http_reply_code=atoi(p);
printf("http_reply_code=%d (%s)\n",m_http_reply_code,tmp);
}
int keep_alive=0;
for (x = hdrstart; x < hdrend-4; x ++)
{
if (!strnicmp((char*)payload+x,"\nTransfer-Encoding:",19))
{
x+=19;
while (payload[x] == ' ' && x < payload_len) x++;
if (!strnicmp((char*)payload+x,"chunked",7))
{
m_ischunked=1;
m_chunkpos=0;
}
}
else if (!strnicmp((char*)payload+x,"\nContent-Type:",14))
{
x+=14;
while (payload[x] == ' ' && x < payload_len) x++;
while (payload[x] != '/' && payload[x] != '\r' && payload[x] != '\n' && x < payload_len) x++;
if (x < payload_len && payload[x] == '/')
{
int sx=++x;
while (payload[x] != '\r' && payload[x] != '\n' && x < payload_len) x++;
if ( x > sx+2 && !strnicmp((char*)payload+sx,"x-",2)) sx+=2; // skip x-
lstrcpyn(m_mime_subtype,(char*)payload+sx,min(sizeof(m_mime_subtype),1+x-sx));
}
}
else if (!strnicmp((char*)payload+x,"\nContent-Encoding:",18))
{
x+=18;
while (payload[x] == ' ' && x < payload_len) x++;
int sx=x;
if (!strnicmp((char*)payload+sx,"gzip",4)) m_is_gz=1;
}
else if (!strnicmp((char*)payload+x,"\nContent-Length:",16))
{
x+=16;
while (payload[x] == ' ' && x < payload_len) x++;
int len=atoi((char*)payload+x);
//printf("Got Content-Length of %d\n",len);
m_content_length_orig = m_content_length = len;
}
else if (m_content_length_orig < 0 && !strnicmp((char*)payload+x,"\nConnection:",12))
{
x+=12;
while (payload[x] == ' ' && x < payload_len) x++;
if (!strnicmp((char*)payload+x,"keep-alive",10)) keep_alive=1;
}
}
if (keep_alive && !m_ischunked && m_content_length_orig < 0)
m_content_length_orig=m_content_length=0;
//printf("got response, keep_alive=%d, content_length=%d, chunked=%d\n",keep_alive, m_content_length_orig, m_ischunked);
return hdrend; // done with header, let the rest get parsed the next time around
}
if (payload_len <= 0) return payload_len;
// at this point, handle the different data types
if (m_ischunked)
{
if (m_chunkpos > 0)
{
int l=min(m_chunkpos,payload_len);
m_chunkpos-=l;
doWrite(payload,l);
return l;
}
char buf[32];
int x=0;
while (x < payload_len && (payload[x] == '\r' || payload[x] == '\n')) x++;
int sx=x;
while (x < payload_len && payload[x] != '\r' && payload[x] != '\n') x++;
lstrcpyn(buf,(char*)payload+sx,min(x-sx+1,sizeof(buf)));
char *p;
// printf("reading chunk from buf: |%s|\n",buf);
m_chunkpos = strtol(buf,&p,16);
if (x < payload_len && payload[x]=='\r') x++;
if (x < payload_len && payload[x]=='\n') x++;
if (!m_chunkpos) // we're done
{
m_done=1;
}
return x;
}
else if (m_content_length_orig >= 0)
{
int l=min(m_content_length,payload_len);
if (l > 0)
{
m_content_length-=l;
doWrite(payload,l);
}
if (m_content_length <= 0)
{
m_done=1;
}
return l;
}
else
{
doWrite(payload,payload_len);
return payload_len; // woot, in non-chunked non-content length mode we just write it all
}
}
void HTTP_context::doWrite(void *buf, int len)
{
if (len < 1) return;
if (m_http_reply_code < 200 || m_http_reply_code >= 300) return;
if (!m_fp && m_fn[0])
{
if (g_config_usemime &&
// stricmp(m_mime_subtype,"octet-stream") &&
// stricmp(m_mime_subtype,"unknown") &&
// stricmp(m_mime_subtype,"binary") &&
stricmp(m_mime_subtype,"misc") &&
strlen(m_mime_subtype) < 5) // the strlen really removes a lot of the above
{
if (m_mime_subtype[0])
{
if (!stricmp(m_mime_subtype,"jpeg")) strcpy(m_mime_subtype,"jpg");
{
char *p=m_mime_subtype;
int c=8;
while (*p && c-- && *p != '?' && *p != '*' && *p != '&' && *p != '/' && *p != '\\' && *p != '|' && *p != ':' && *p != ' ' && *p != ';') p++;
*p=0;
}
}
if (m_mime_subtype[0])
{
if (g_config_usemime>1) {
char *p=m_fn;
while (*p) p++;
int c=16;
while (*p != '/' && *p != '?' && *p != '&' && *p != '.' && p > m_fn && c-- > 0) p--;
if (*p == '.') *p=0; // remove extension
}
strcat(m_fn,".");
strcat(m_fn,m_mime_subtype);
}
}
if (g_config_debugfn)
sprintf(finalfn,"%s/"
"%s"
"(%02d%s%s)" // woot
"%s%s",
g_config_leadpath,
m_host,
m_concnt,m_ischunked?"ch":"",m_is_gz?"gz":"",
m_fn,m_is_gz ? ".gz" : "");
else
sprintf(finalfn,"%s/"
"%s"
"%s%s",
g_config_leadpath,
m_host,
m_fn,m_is_gz ? ".gz" : "");
{
char *p=finalfn;
while ((p=strstr(p,".."))) p[1]='_';
p=finalfn+2;
while ((p=strstr(p,"\\\\"))) p[1]='_';
p=finalfn;
while ((p=strstr(p,"//"))) p[1]='_';
}
if (g_config_subdirs)
{
char *p=finalfn;
if (*p)
{
#ifdef _WIN32
p = skip_root(finalfn);
#else
p=finalfn;
#endif
if (p) for (;;)
{
while (!IS_DIR_CHAR(*p) && *p) p=CharNext(p);
if (!*p) break;
char c=*p;
*p=0;
#ifdef _WIN32
CreateDirectory(finalfn,NULL);
#else
mkdir(finalfn,0644);
#endif
*p++ = c;
}
}
}
if (finalfn[0] && IS_DIR_CHAR(finalfn[strlen(finalfn)-1])) strcat(finalfn,"index.html");
m_fp = fopen(finalfn,"wb");
if (!m_fp)
printf("Error creating '%s'\n",finalfn);
}
if (m_fp)
{
fwrite(buf,len,1,m_fp);
fflush(m_fp);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -